package com.spsoft.vatoutinv.service.vmsmanualinvoice.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BusinessException;
import com.spsoft.core.listener.ExcelListener;
import com.spsoft.core.model.Result;
import com.spsoft.core.model.bo.TokenUser;
import com.spsoft.core.utils.BeanUtils;
import com.spsoft.core.utils.SecurityUtils;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.vatoutinv.constants.CommonConstant;
import com.spsoft.vatoutinv.constants.DictConstant;
import com.spsoft.vatoutinv.entity.vmsclassifycode.VmsClassifyCode;
import com.spsoft.vatoutinv.entity.vmsenterpriseinfo.VmsEnterpriseInfo;
import com.spsoft.vatoutinv.entity.vmsenterpriseinforisk.VmsEnterpriseInfoRisk;
import com.spsoft.vatoutinv.entity.vmsepsInformation.VmsEpsInformation;
import com.spsoft.vatoutinv.entity.vmsfullbswjmanager.VmsFullBswjManager;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.*;
import com.spsoft.vatoutinv.entity.vmsmanualinvoice.*;
import com.spsoft.vatoutinv.entity.vmsmanualinvoice.excel.VmsManualBaseExcel;
import com.spsoft.vatoutinv.entity.vmsmanualinvoice.excel.VmsManualDetailExcel;
import com.spsoft.vatoutinv.entity.vmsmanualinvoice.excel.VmsManualExtendExcel;
import com.spsoft.vatoutinv.entity.vmsmanualinvoice.excel.VmsManualTdywExcel;
import com.spsoft.vatoutinv.enums.CheckParamEnum;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.enums.TdysEnum;
import com.spsoft.vatoutinv.mapper.VmsManualBaseMapper;
import com.spsoft.vatoutinv.model.dto.vmsfulloutinvoice.VmsFullOutInvoiceInfoDto;
import com.spsoft.vatoutinv.model.dto.vmsmanualinvoice.*;
import com.spsoft.vatoutinv.model.vo.issueinvoice.ErrorVerifyVo;
import com.spsoft.vatoutinv.model.vo.vmsmanualinvoice.*;
import com.spsoft.vatoutinv.service.issueinvoice.CheckDataService;
import com.spsoft.vatoutinv.service.issueinvoice.IssueInvoiceService;
import com.spsoft.vatoutinv.service.pricetaxseparation.PriceTaxSeparationService;
import com.spsoft.vatoutinv.service.translate.impl.DictTranslate;
import com.spsoft.vatoutinv.service.vmsclassifycode.VmsClassifyCodeService;
import com.spsoft.vatoutinv.service.vmsenterpriseinfo.VmsEnterpriseInfoService;
import com.spsoft.vatoutinv.service.vmsenterpriseinforisk.VmsEnterpriseInfoRiskService;
import com.spsoft.vatoutinv.service.vmsepsInformation.VmsEpsInformationService;
import com.spsoft.vatoutinv.service.vmsfullbswjmanager.VmsFullBswjManagerService;
import com.spsoft.vatoutinv.service.vmsmanualinvoice.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 手工开票临时表-主表 服务实现类
 * </p>
 *
 * @author chenxudong
 * @since 2023-11-30
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VmsManualBaseServiceImpl extends ServiceImpl<VmsManualBaseMapper, VmsManualBase> implements VmsManualBaseService {

    public static final String LOG_MSG = "(手工发票开具实现层)";

    private final VmsEnterpriseInfoService vmsEnterpriseInfoService;

    private final VmsEnterpriseInfoRiskService vmsEnterpriseInfoRiskService;

    private final VmsManualDetailService vmsManualDetailService;

    private final VmsManualExtendService vmsManualExtendService;

    private final VmsManualAddService vmsManualAddService;

    private final VmsManualBaseMapper vmsManualBaseMapper;

    private final VmsManualTdywService vmsManualTdywService;

    private final VmsManualTdywItemService vmsManualTdywItemService;

    private final VmsManualCekcService vmsManualCekcService;

    private final VmsFullBswjManagerService vmsFullBswjManagerService;

    private final PriceTaxSeparationService priceTaxSeparationService;

    private final VmsClassifyCodeService vmsClassifyCodeService;

    private final IssueInvoiceService issueInvoiceService;

    private final VmsEpsInformationService vmsEpsInformationService;

    private final CheckDataService checkDataService;

    private final DictTranslate dictTranslate;

    @Override
    public Result<Object> checkBeforeAdd(String deptCode) {
        // 根据当前登录机构的纳税人识别号获取纳税人基本信息
        VmsEnterpriseInfo vmsEnterpriseInfo = vmsEnterpriseInfoService.getInfoByRedis(deptCode);
        log.info("{}获取到的纳税人基本信息：{}", LOG_MSG, JSONObject.toJSONString(vmsEnterpriseInfo));

        // 根据当前登录机构的纳税人识别号获取纳税人风险信息
        VmsEnterpriseInfoRisk vmsEnterpriseInfoRisk = vmsEnterpriseInfoRiskService.getRiskInfoByRedis(deptCode);
        log.info("{}获取到的纳税人风险信息：{}", LOG_MSG, JSONObject.toJSONString(vmsEnterpriseInfoRisk));

        // 校验纳税人基本信息和纳税人风险信息
        ResponseEnum responseEnum = checkEnterpriseInfoAndRisk(vmsEnterpriseInfo, vmsEnterpriseInfoRisk);
        if (!ResponseEnum.SUCCESS.getCode().equals(responseEnum.getCode())) {
            log.error("{}新增发票前的校验，返回错误信息：{}", LOG_MSG, responseEnum.getMsg());
            return Result.ERROR(responseEnum);
        }

        return Result.OK();
    }

    @Override
    public Result<VmsManualDefaultVo> getBaseInfo(TokenUser tokenUser) {
        // 手工开票-新增发票获取默认带出数据实体
        VmsManualDefaultVo defaultVo = new VmsManualDefaultVo();

        // 根据当前登录机构的纳税人识别号获取纳税人基本信息
        VmsEnterpriseInfo vmsEnterpriseInfo = vmsEnterpriseInfoService.getInfoByRedis(tokenUser.getDeptCode());
        log.info("{}获取到的纳税人基本信息：{}", LOG_MSG, JSONObject.toJSONString(vmsEnterpriseInfo));
        if (vmsEnterpriseInfo != null) {
            // 获取销售方信息
            defaultVo.setKpr(tokenUser.getUserName());
            defaultVo.setXsfmc(vmsEnterpriseInfo.getNsrmc());
            defaultVo.setXsfnsrsbh(vmsEnterpriseInfo.getNsrsbh());
            defaultVo.setXsfdz(vmsEnterpriseInfo.getScjydz());
            defaultVo.setXsfdh(vmsEnterpriseInfo.getZcdlxdh());
            defaultVo.setXsfkhh(vmsEnterpriseInfo.getKhhmc());
            defaultVo.setXsfzh(vmsEnterpriseInfo.getYhzh());
            // 获取行业代码
            defaultVo.setHydm(vmsEnterpriseInfo.getHydm());
        }

        // 根据当前登录机构的纳税人识别号获取版式文件信息
        VmsFullBswjManager vmsFullBswj = vmsFullBswjManagerService.getOneByWhjg(tokenUser.getDeptCode());
        log.info("{}获取到的数电发票版式文件信息：{}", LOG_MSG, JSONObject.toJSONString(vmsFullBswj));
        if (vmsFullBswj != null) {
            // 获取区域代码
            defaultVo.setQydm(vmsFullBswj.getQydm());
        }

        return Result.OK(defaultVo);
    }

    @Override
    public Result<IPage<VmsManualBaseVo>> getPageInfo(VmsManualPageDto vmsManualPageDto) {
        // 根据审批流id获取发票分页信息
        Page<VmsManualBase> page = new Page<>(vmsManualPageDto.getPageNo(), vmsManualPageDto.getPageSize());
        IPage<VmsManualBase> IPage = vmsManualBaseMapper.queryBaseInfo(page, vmsManualPageDto.getApplyId());

        // 将数据库返回数据转换为VO返回前端
        IPage<VmsManualBaseVo> IPageVo = IPage.convert(item -> {
            VmsManualBaseVo vo = new VmsManualBaseVo();
            // 转换数据
            BeanUtils.copyBeanProp(vo, item);
            return vo;
        });

        return Result.OK(IPageVo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> checkAndSave(VmsManualInvoiceDto vmsManualInvoiceDto, TokenUser tokenUser) {

        if (ObjectUtil.isNull(vmsManualInvoiceDto)) {
            return Result.ERROR(ResponseEnum.BUSINESS_MANUAL_EMPTY_ERROR);
        }
        if (ObjectUtil.isNull(vmsManualInvoiceDto.getVmsManualBaseDto())) {
            return Result.ERROR(ResponseEnum.BUSINESS_MANUAL_EMPTY2_ERROR);
        }
        if (CollectionUtil.isEmpty(vmsManualInvoiceDto.getVmsManualDetailDtoList())) {
            return Result.ERROR(ResponseEnum.BUSINESS_MANUAL_EMPTY3_ERROR);
        }

        // 必填项、数据合法性校验
        List<String> errMsgList = checkManualData(vmsManualInvoiceDto);
        if (CollectionUtil.isNotEmpty(errMsgList)) {
            log.error("{}手工开票数据合法性校验不通过，错误信息：{}", LOG_MSG, JSONObject.toJSONString(errMsgList));
            return Result.ERROR(ResponseEnum.BUSINESS_MANUAL_VERIFY_ERROR, errMsgList);
        }

        // 数据转换并进行业务逻辑校验
        VmsFullOutInvoiceInfoDto vmsFullOutInvoiceInfoDto = convertToVmsFullOutInvoiceInfoDto(vmsManualInvoiceDto);
        List<VmsFullOutInvoiceInfoDto> invoiceDtoList = new ArrayList<>();
        invoiceDtoList.add(vmsFullOutInvoiceInfoDto);
        List<ErrorVerifyVo> errorVerifyVoList = checkDataService.checkDataBusiness(invoiceDtoList,
                tokenUser.getDeptCode(), CommonEnum.CHECK_SOURCE_0.getKey());
        if (CollectionUtil.isNotEmpty(errorVerifyVoList)) {
            log.error("{}手工开票业务逻辑校验不通过，错误信息：{}", LOG_MSG, JSONObject.toJSONString(errorVerifyVoList));
            return Result.ERROR(ResponseEnum.ISSUE_INVOICE_VERIFY_ERROR, errorVerifyVoList);
        }

        // 发票主信息
        VmsManualBaseDto baseDto = vmsManualInvoiceDto.getVmsManualBaseDto();
        // 发票明细信息
        List<VmsManualDetailDto> detailDtoList = vmsManualInvoiceDto.getVmsManualDetailDtoList();
        // 非必填字段扩展信息
        VmsManualExtendDto extendDto = vmsManualInvoiceDto.getVmsManualExtendDto();
        // 附加要素信息
        List<VmsManualAddDto> addDtoList = vmsManualInvoiceDto.getVmsManualAddDtoList();
        // 特定业务信息
        List<VmsManualTdywDto> tdywDtoList = vmsManualInvoiceDto.getVmsManualTdywDtoList();
        // 差额扣除信息
        List<VmsManualCekcDto> cekcDtoList = vmsManualInvoiceDto.getVmsManualCekcDtoList();

        if (baseDto.getApplyId() == null || baseDto.getApplyId() == 0) {
            return Result.ERROR(ResponseEnum.APPLY_ID_EMPTY_ERROR);
        }

        // 校验通过，数据入库
        log.info("{}新增发票数据校验通过，开始入库", LOG_MSG);

        // 保存发票主信息
        VmsManualBase base = new VmsManualBase();
        BeanUtils.copyBeanProp(base, baseDto);
        base.setId(null);
        base.setQydjid(tokenUser.getDeptCode());
        base.setCreatTime(new Date());
        base.setCreatBy(tokenUser.getUserCode());
        base.setUpdateTime(new Date());
        base.setUpdateBy(tokenUser.getUserCode());
        log.info("{}保存手工开票发票主信息", LOG_MSG);
        this.save(base);

        // 保存发票明细信息
        List<VmsManualDetail> detailList = new ArrayList<>();
        for (int i = 0; i < detailDtoList.size(); i++) {
            VmsManualDetailDto detailDto = detailDtoList.get(i);
            VmsManualDetail detail = new VmsManualDetail();
            BeanUtils.copyBeanProp(detail, detailDto);
            detail.setId(null);
            detail.setMxxh((long) (i + 1));
            detail.setBaseId(base.getId());
            // 金额模式处理
            if (CommonConstant.STR_02.equals(base.getJems())) {
                detail.setHsdj(detail.getDj());
            }
            if (CommonEnum.CEZS_01.getKey().equals(base.getCezslxdm())) {
                // 全额开票将扣除额置为0
                detail.setKce(BigDecimal.ZERO);
            } else if (StringUtils.isBlank(base.getCezslxdm())) {
                // 非差额开票扣除额置为空
                detail.setKce(null);
            }
            detail.setCreatTime(new Date());
            detail.setCreatBy(tokenUser.getUserCode());

            // 根据存在的税收分类编码补全或修改明细的项目简称
            if (StringUtils.isNotBlank(detail.getSphfwssflhbbm())) {
                LambdaQueryWrapper<VmsClassifyCode> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(VmsClassifyCode::getSphfwssflhbbm, detail.getSphfwssflhbbm());
                queryWrapper.eq(VmsClassifyCode::getDeptCode, tokenUser.getDeptCode());
                VmsClassifyCode vmsClassifyCode = vmsClassifyCodeService.getOne(queryWrapper);
                if (vmsClassifyCode != null) {
                    // 如果项目名称为空,使用乐企返回数据进行补全,如果不为空且需要补全,则进行补全
                    String spmc = detail.getXmmc();
                    StringBuilder stringBuilder = new StringBuilder();
                    if (StringUtils.isBlank(spmc)) {
                        spmc = stringBuilder.append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwfljc()).append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwmc()).toString();
                    } else if (StringUtil.checkXmmc(spmc, vmsClassifyCode.getSphfwfljc())) {
                        spmc = stringBuilder.append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwfljc()).append(CommonConstant.STRING_STAR).append(spmc).toString();
                    }
                    detail.setXmmc(spmc);
                }
            }

            detailList.add(detail);
        }
        // 不动产销售、不动产租赁，明细行数据补全
        if (StrUtil.equalsAny(base.getTdys(), CommonEnum.TDYS_05.getKey(), CommonEnum.TDYS_06.getKey())) {
            // 不动产销售、不动产租赁明细行和特定业务有且只有一行
            VmsManualDetail vmsManualDetail = detailList.get(0);
            VmsManualTdywDto vmsManualTdywDto = tdywDtoList.get(0);
            if (StringUtils.isNotBlank(vmsManualTdywDto.getCqzsbh())) {
                vmsManualDetail.setGgxh(vmsManualTdywDto.getCqzsbh());
            }
            if (StringUtils.isNotBlank(vmsManualTdywDto.getMjdw())) {
                vmsManualDetail.setDw(vmsManualTdywDto.getMjdw());
            }
        }
        log.info("{}保存手工开票发票明细信息", LOG_MSG);
        vmsManualDetailService.saveBatch(detailList);

        // 保存非必填字段扩展信息
        if (extendDto != null) {
            VmsManualExtend extend = new VmsManualExtend();
            BeanUtils.copyBeanProp(extend, extendDto);
            extend.setId(null);
            extend.setBaseId(base.getId());
            log.info("{}保存手工开票非必填字段扩展信息", LOG_MSG);
            vmsManualExtendService.save(extend);
        }

        // 保存附加要素信息
        if (CollectionUtil.isNotEmpty(addDtoList)) {
            List<VmsManualAdd> addList = new ArrayList<>();
            for (VmsManualAddDto vmsManualAddDto : addDtoList) {
                VmsManualAdd add = new VmsManualAdd();
                BeanUtils.copyBeanProp(add, vmsManualAddDto);
                add.setId(null);
                add.setBaseId(base.getId());

                addList.add(add);
            }
            log.info("{}保存手工开票附加要素信息", LOG_MSG);
            vmsManualAddService.saveBatch(addList);
        }

        // 保存特定业务信息
        if (CollectionUtil.isNotEmpty(tdywDtoList)) {
            // 不动产销售服务发票、不动产租赁服务发票 特定业务信息只有一条
            // 旅客运输服务发票 特定业务信息可以有多条
            if (CommonEnum.TDYS_05.getKey().equals(baseDto.getTdys())
                    || CommonEnum.TDYS_06.getKey().equals(baseDto.getTdys())
                    || CommonEnum.TDYS_09.getKey().equals(baseDto.getTdys())) {
                for (VmsManualTdywDto tdywDto : tdywDtoList) {
                    VmsManualTdyw tdyw = new VmsManualTdyw();
                    BeanUtils.copyBeanProp(tdyw, tdywDto);
                    tdyw.setTdywId(null);
                    tdyw.setBaseId(base.getId());
                    log.info("{}保存手工开票特定业务信息", LOG_MSG);
                    vmsManualTdywService.save(tdyw);

                    // 不动产销售服务发票，多方共同购买处理
                    if (CommonEnum.TDYS_05.getKey().equals(baseDto.getTdys())
                            && CommonConstant.STR_Y.equals(tdywDto.getDfgtgmbz())) {
                        List<VmsManualTdywItemDto> gtgmfList = tdywDto.getTdywItemList();
                        List<VmsManualTdywItem> tdywItemList = BeanUtils.copyListProperties(gtgmfList, VmsManualTdywItem::new, (s, t) -> {
                            t.setId(null);
                            t.setTdywId(tdyw.getTdywId());
                        });
                        log.info("{}保存手工开票特定业务附加信息", LOG_MSG);
                        vmsManualTdywItemService.saveBatch(tdywItemList);
                    }
                }
            }
        }

        // 差额扣除信息
        if (CollectionUtil.isNotEmpty(cekcDtoList)) {
            if (CommonEnum.CEZS_02.getKey().equals(baseDto.getCezslxdm())) {
                List<VmsManualCekc> cekcList = new ArrayList<>();
                for (int i = 0; i < cekcDtoList.size(); i++) {
                    VmsManualCekcDto vmsManualCekcDto = cekcDtoList.get(i);
                    VmsManualCekc vmsManualCekc = new VmsManualCekc();
                    BeanUtils.copyBeanProp(vmsManualCekc, vmsManualCekcDto);
                    vmsManualCekc.setId(null);
                    vmsManualCekc.setXh((long) (i + 1));
                    vmsManualCekc.setBaseId(base.getId());

                    cekcList.add(vmsManualCekc);
                }
                log.info("{}保存手工开票差额扣除信息", LOG_MSG);
                vmsManualCekcService.saveBatch(cekcList);
            }
        }

        return Result.OK();
    }

    /**
     * 将手工开票Dto转换为已开发票Dto，用于后续业务校验
     * @param vmsManualInvoiceDto 手工开票Dto
     * @return 已开发票Dto
     */
    private VmsFullOutInvoiceInfoDto convertToVmsFullOutInvoiceInfoDto(VmsManualInvoiceDto vmsManualInvoiceDto) {
        VmsFullOutInvoiceInfoDto vmsFullOutInvoiceInfoDto = new VmsFullOutInvoiceInfoDto();

        // 转换发票主信息
        VmsFullOutInvoiceDetails vmsFullOutInvoiceDetails = new VmsFullOutInvoiceDetails();
        VmsManualBaseDto vmsManualBaseDto = vmsManualInvoiceDto.getVmsManualBaseDto();
        BeanUtils.copyProperties(vmsManualBaseDto, vmsFullOutInvoiceDetails);
        vmsFullOutInvoiceDetails.setLzfpbz(CommonEnum.INVOICE_BLUE.getKey());
        vmsFullOutInvoiceDetails.setSjly(CommonEnum.DATA_SOURCE_1.getKey());
        vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceDetails(vmsFullOutInvoiceDetails);

        // 转换发票明细信息
        List<VmsManualDetailDto> vmsManualDetailDtoList = vmsManualInvoiceDto.getVmsManualDetailDtoList();
        List<VmsFullOutInvoiceItems> invoiceItemsList = BeanUtils.copyListProperties(vmsManualDetailDtoList, VmsFullOutInvoiceItems::new);
        vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceItemsList(invoiceItemsList);

        // 转换发票非必填扩展信息
        VmsManualExtendDto vmsManualExtendDto = vmsManualInvoiceDto.getVmsManualExtendDto();
        if (ObjectUtil.isNotEmpty(vmsManualExtendDto)) {
            VmsFullOutInvoiceItemsExp vmsFullOutInvoiceItemsExp = new VmsFullOutInvoiceItemsExp();
            BeanUtils.copyProperties(vmsManualExtendDto, vmsFullOutInvoiceItemsExp);
            vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceItemsExp(vmsFullOutInvoiceItemsExp);
        }

        // 转换发票附加要素信息
        List<VmsManualAddDto> vmsManualAddDtoList = vmsManualInvoiceDto.getVmsManualAddDtoList();
        if (CollectionUtil.isNotEmpty(vmsManualAddDtoList)) {
            List<VmsFullOutInvoiceItemsAdd> invoiceItemsAddList = BeanUtils.copyListProperties(vmsManualAddDtoList, VmsFullOutInvoiceItemsAdd::new);
            vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceItemsAddList(invoiceItemsAddList);
        }

        // 转换发票特定业务信息
        List<VmsManualTdywDto> vmsManualTdywDtoList = vmsManualInvoiceDto.getVmsManualTdywDtoList();
        if (CollectionUtil.isNotEmpty(vmsManualTdywDtoList)) {
            List<VmsFullOutInvoiceTdyw> invoiceTdywList = new ArrayList<>();
            for (VmsManualTdywDto vmsManualTdywDto : vmsManualTdywDtoList) {
                VmsFullOutInvoiceTdyw invoiceTdyw = new VmsFullOutInvoiceTdyw();
                BeanUtils.copyProperties(vmsManualTdywDto, invoiceTdyw);
                // 特定业务附加信息List
                if (CollectionUtil.isNotEmpty(vmsManualTdywDto.getTdywItemList())) {
                    List<VmsFullOutInvoiceTdywItem> invoiceTdywItemList = BeanUtils.copyListProperties(vmsManualTdywDto.getTdywItemList(), VmsFullOutInvoiceTdywItem::new);
                    invoiceTdyw.setTdywItemList(invoiceTdywItemList);
                }
                invoiceTdywList.add(invoiceTdyw);
            }
            vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceTdywList(invoiceTdywList);
        }

        // 转换发票差额扣除信息
        List<VmsManualCekcDto> vmsManualCekcDtoList = vmsManualInvoiceDto.getVmsManualCekcDtoList();
        if (CollectionUtil.isNotEmpty(vmsManualCekcDtoList)) {
            List<VmsFullOutInvoiceCekc> invoiceCekcList = BeanUtils.copyListProperties(vmsManualCekcDtoList, VmsFullOutInvoiceCekc::new);
            vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceCekcList(invoiceCekcList);
        }

        return vmsFullOutInvoiceInfoDto;
    }

    /**
     * 将Excel导入数据集合转换为已开发票集合，用于后续业务校验
     * @param invoiceList Excel导入数据集合
     * @return 已开发票集合
     */
    private List<VmsFullOutInvoiceInfoDto> convertToVmsFullOutInvoiceInfoDtoList(List<VmsManualInvoice> invoiceList) {
        List<VmsFullOutInvoiceInfoDto> vmsFullOutInvoiceInfoDtoList = new ArrayList<>();

        for (VmsManualInvoice vmsManualInvoice : invoiceList) {
            VmsFullOutInvoiceInfoDto vmsFullOutInvoiceInfoDto = new VmsFullOutInvoiceInfoDto();

            // 转换发票主信息
            VmsFullOutInvoiceDetails vmsFullOutInvoiceDetails = new VmsFullOutInvoiceDetails();
            VmsManualBase vmsManualBase = vmsManualInvoice.getVmsManualBase();
            BeanUtils.copyProperties(vmsManualBase, vmsFullOutInvoiceDetails);
            vmsFullOutInvoiceDetails.setLzfpbz(CommonEnum.INVOICE_BLUE.getKey());
            vmsFullOutInvoiceDetails.setSjly(CommonEnum.DATA_SOURCE_1.getKey());
            vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceDetails(vmsFullOutInvoiceDetails);

            // 转换发票明细信息
            List<VmsManualDetail> vmsManualDetailList = vmsManualInvoice.getVmsManualDetailList();
            List<VmsFullOutInvoiceItems> invoiceItemsList = BeanUtils.copyListProperties(vmsManualDetailList, VmsFullOutInvoiceItems::new);
            vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceItemsList(invoiceItemsList);

            // 转换发票非必填扩展信息
            VmsManualExtend vmsManualExtend = vmsManualInvoice.getVmsManualExtend();
            if (ObjectUtil.isNotEmpty(vmsManualExtend)) {
                VmsFullOutInvoiceItemsExp vmsFullOutInvoiceItemsExp = new VmsFullOutInvoiceItemsExp();
                BeanUtils.copyProperties(vmsManualExtend, vmsFullOutInvoiceItemsExp);
                vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceItemsExp(vmsFullOutInvoiceItemsExp);
            }

            // 转换发票附加要素信息
            List<VmsManualAdd> vmsManualAddList = vmsManualInvoice.getVmsManualAddList();
            if (CollectionUtil.isNotEmpty(vmsManualAddList)) {
                List<VmsFullOutInvoiceItemsAdd> invoiceItemsAddList = BeanUtils.copyListProperties(vmsManualAddList, VmsFullOutInvoiceItemsAdd::new);
                vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceItemsAddList(invoiceItemsAddList);
            }

            // 转换发票特定业务信息
            List<VmsManualTdyw> vmsManualTdywList = vmsManualInvoice.getVmsManualTdywList();
            if (CollectionUtil.isNotEmpty(vmsManualTdywList)) {
                List<VmsFullOutInvoiceTdyw> invoiceTdywList = new ArrayList<>();
                for (VmsManualTdyw vmsManualTdyw : vmsManualTdywList) {
                    VmsFullOutInvoiceTdyw invoiceTdyw = new VmsFullOutInvoiceTdyw();
                    BeanUtils.copyProperties(vmsManualTdyw, invoiceTdyw);
                    // 特定业务附加信息List
                    if (CollectionUtil.isNotEmpty(vmsManualTdyw.getTdywItemList())) {
                        List<VmsFullOutInvoiceTdywItem> invoiceTdywItemList = BeanUtils.copyListProperties(vmsManualTdyw.getTdywItemList(), VmsFullOutInvoiceTdywItem::new);
                        invoiceTdyw.setTdywItemList(invoiceTdywItemList);
                    }
                    invoiceTdywList.add(invoiceTdyw);
                }
                vmsFullOutInvoiceInfoDto.setVmsFullOutInvoiceTdywList(invoiceTdywList);
            }

            vmsFullOutInvoiceInfoDtoList.add(vmsFullOutInvoiceInfoDto);
        }

        return vmsFullOutInvoiceInfoDtoList;
    }

    @Override
    public Result<VmsManualInvoiceVo> getInvoiceInfo(Long baseId) {
        // 发票信息数据Vo实体
        VmsManualInvoiceVo invoiceVo = new VmsManualInvoiceVo();

        // 根据发票id获取发票信息
        LambdaQueryWrapper<VmsManualBase> baseQueryWrapper = new LambdaQueryWrapper<>();
        baseQueryWrapper.eq(VmsManualBase::getId, baseId);
        VmsManualBase base = this.getOne(baseQueryWrapper);
        if (base == null) {
            return Result.ERROR(ResponseEnum.INVOICE_NOT_FIND_ERROR);
        }

        VmsManualBaseVo baseVo = new VmsManualBaseVo();
        BeanUtils.copyProperties(base, baseVo);
        invoiceVo.setVmsManualBaseVo(baseVo);

        // 发票明细信息
        LambdaQueryWrapper<VmsManualDetail> detailQueryWrapper = new LambdaQueryWrapper<>();
        detailQueryWrapper.eq(VmsManualDetail::getBaseId, base.getId());
        detailQueryWrapper.orderByAsc(VmsManualDetail::getMxxh);
        List<VmsManualDetail> detailList = vmsManualDetailService.list(detailQueryWrapper);
        List<VmsManualDetailVo> detailVoList = BeanUtils.copyListProperties(detailList, VmsManualDetailVo::new);
        invoiceVo.setVmsManualDetailVoList(detailVoList);

        // 非必填字段扩展信息
        LambdaQueryWrapper<VmsManualExtend> extendQueryWrapper = new LambdaQueryWrapper<>();
        extendQueryWrapper.eq(VmsManualExtend::getBaseId, base.getId());
        VmsManualExtend extend = vmsManualExtendService.getOne(extendQueryWrapper);
        if (extend != null) {
            VmsManualExtendVo extendVo = new VmsManualExtendVo();
            BeanUtils.copyProperties(extend, extendVo);
            invoiceVo.setVmsManualExtendVo(extendVo);
        }

        // 附加要素信息
        LambdaQueryWrapper<VmsManualAdd> addQueryWrapper = new LambdaQueryWrapper<>();
        addQueryWrapper.eq(VmsManualAdd::getBaseId, base.getId());
        addQueryWrapper.orderByAsc(VmsManualAdd::getId);
        List<VmsManualAdd> addList = vmsManualAddService.list(addQueryWrapper);
        if (CollectionUtil.isNotEmpty(addList)) {
            List<VmsManualAddVo> addVoList = BeanUtils.copyListProperties(addList, VmsManualAddVo::new);
            invoiceVo.setVmsManualAddVoList(addVoList);
        }

        // 特定业务信息
        if (CommonEnum.TDYS_05.getKey().equals(base.getTdys())
                || CommonEnum.TDYS_06.getKey().equals(base.getTdys())
                || CommonEnum.TDYS_09.getKey().equals(base.getTdys())) {
            // 查询特定业务信息
            LambdaQueryWrapper<VmsManualTdyw> query = new LambdaQueryWrapper<>();
            query.eq(VmsManualTdyw::getBaseId, base.getId());
            query.orderByAsc(VmsManualTdyw::getTdywId);
            List<VmsManualTdyw> tdywList = vmsManualTdywService.list(query);
            List<VmsManualTdywVo> tdywVoList = BeanUtils.copyListProperties(tdywList, VmsManualTdywVo::new);

            for (VmsManualTdywVo tdywVo : tdywVoList) {
                if (CommonEnum.TDYS_05.getKey().equals(base.getTdys())
                        && CommonConstant.STR_Y.equals(tdywVo.getDfgtgmbz())) {
                    // 查询不动产销售 特定业务附加信息
                    LambdaQueryWrapper<VmsManualTdywItem> itemQuery = new LambdaQueryWrapper<>();
                    itemQuery.eq(VmsManualTdywItem::getTdywId, tdywVo.getTdywId());
                    itemQuery.orderByAsc(VmsManualTdywItem::getId);
                    List<VmsManualTdywItem> tdywItemList = vmsManualTdywItemService.list(itemQuery);
                    if (CollectionUtil.isNotEmpty(tdywItemList)) {
                        List<VmsManualTdywItemVo> tdywItemVoList = BeanUtils.copyListProperties(tdywItemList, VmsManualTdywItemVo::new);
                        tdywVo.setTdywItemVoList(tdywItemVoList);
                    }
                }
            }

            invoiceVo.setVmsManualTdywVoList(tdywVoList);
        }

        // 差额扣除信息
        if (CommonEnum.CEZS_02.getKey().equals(base.getCezslxdm())) {
            LambdaQueryWrapper<VmsManualCekc> cekcQueryWrapper = new LambdaQueryWrapper<>();
            cekcQueryWrapper.eq(VmsManualCekc::getBaseId, base.getId());
            cekcQueryWrapper.orderByAsc(VmsManualCekc::getId);
            List<VmsManualCekc> cekcList = vmsManualCekcService.list(cekcQueryWrapper);
            if (CollectionUtil.isNotEmpty(cekcList)) {
                List<VmsManualCekcVo> cekcVoList = BeanUtils.copyListProperties(cekcList, VmsManualCekcVo::new);
                invoiceVo.setVmsManualCekcVoList(cekcVoList);
            }
        }

        return Result.OK(invoiceVo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> updateInvoice(VmsManualInvoiceDto vmsManualInvoiceDto, TokenUser tokenUser) {

        if (ObjectUtil.isNull(vmsManualInvoiceDto)) {
            return Result.ERROR(ResponseEnum.BUSINESS_MANUAL_EMPTY_ERROR);
        }
        if (ObjectUtil.isNull(vmsManualInvoiceDto.getVmsManualBaseDto())) {
            return Result.ERROR(ResponseEnum.BUSINESS_MANUAL_EMPTY2_ERROR);
        }
        if (CollectionUtil.isEmpty(vmsManualInvoiceDto.getVmsManualDetailDtoList())) {
            return Result.ERROR(ResponseEnum.BUSINESS_MANUAL_EMPTY3_ERROR);
        }

        // 必填项、数据合法性校验
        List<String> errMsgList = checkManualData(vmsManualInvoiceDto);

        if (CollectionUtil.isNotEmpty(errMsgList)) {
            return Result.ERROR(ResponseEnum.BUSINESS_MANUAL_VERIFY_ERROR, errMsgList);
        }

        // 数据转换并进行业务逻辑校验
        VmsFullOutInvoiceInfoDto vmsFullOutInvoiceInfoDto = convertToVmsFullOutInvoiceInfoDto(vmsManualInvoiceDto);
        List<VmsFullOutInvoiceInfoDto> invoiceDtoList = new ArrayList<>();
        invoiceDtoList.add(vmsFullOutInvoiceInfoDto);
        List<ErrorVerifyVo> errorVerifyVoList = checkDataService.checkDataBusiness(invoiceDtoList,
                tokenUser.getDeptCode(), CommonEnum.CHECK_SOURCE_0.getKey());
        if (CollectionUtil.isNotEmpty(errorVerifyVoList)) {
            log.error("{}手工开票业务逻辑校验不通过，错误信息：{}", LOG_MSG, JSONObject.toJSONString(errorVerifyVoList));
            return Result.ERROR(ResponseEnum.ISSUE_INVOICE_VERIFY_ERROR, errorVerifyVoList);
        }

        // 发票主信息
        VmsManualBaseDto baseDto = vmsManualInvoiceDto.getVmsManualBaseDto();
        // 发票明细信息
        List<VmsManualDetailDto> detailDtoList = vmsManualInvoiceDto.getVmsManualDetailDtoList();
        // 非必填字段扩展信息
        VmsManualExtendDto extendDto = vmsManualInvoiceDto.getVmsManualExtendDto();
        // 附加要素信息
        List<VmsManualAddDto> addDtoList = vmsManualInvoiceDto.getVmsManualAddDtoList();
        // 特定业务信息
        List<VmsManualTdywDto> tdywDtoList = vmsManualInvoiceDto.getVmsManualTdywDtoList();
        // 差额扣除信息
        List<VmsManualCekcDto> cekcDtoList = vmsManualInvoiceDto.getVmsManualCekcDtoList();

        if (baseDto.getApplyId() == null || baseDto.getApplyId() == 0) {
            return Result.ERROR(ResponseEnum.APPLY_ID_EMPTY_ERROR);
        }

        // 校验通过，数据入库
        log.info("{}更新发票数据校验通过，开始入库", LOG_MSG);

        // 更新发票主信息
        VmsManualBase base = new VmsManualBase();
        BeanUtils.copyBeanProp(base, baseDto);
        base.setQydjid(tokenUser.getDeptCode());
        base.setUpdateTime(new Date());
        base.setUpdateBy(tokenUser.getUserCode());
        log.info("{}更新手工开票发票主信息", LOG_MSG);
        this.updateById(base);

        // 更新发票明细信息，先删除原明细，在插入新明细
        LambdaQueryWrapper<VmsManualDetail> detailQueryWrapper = new LambdaQueryWrapper<>();
        detailQueryWrapper.eq(VmsManualDetail::getBaseId, base.getId());
        vmsManualDetailService.remove(detailQueryWrapper);

        List<VmsManualDetail> detailList = new ArrayList<>();
        for (int i = 0; i < detailDtoList.size(); i++) {
            VmsManualDetailDto detailDto = detailDtoList.get(i);
            VmsManualDetail detail = new VmsManualDetail();
            BeanUtils.copyBeanProp(detail, detailDto);
            detail.setId(null);
            detail.setMxxh((long) (i + 1));
            detail.setBaseId(base.getId());
            // 金额模式处理
            if (CommonConstant.STR_02.equals(base.getJems())) {
                detail.setHsdj(detail.getDj());
            }
            if (CommonEnum.CEZS_01.getKey().equals(base.getCezslxdm())) {
                // 全额开票将扣除额置为0
                detail.setKce(BigDecimal.ZERO);
            } else if (StringUtils.isBlank(base.getCezslxdm())) {
                // 非差额开票扣除额置为空
                detail.setKce(null);
            }
            detail.setCreatTime(new Date());
            detail.setCreatBy(tokenUser.getUserCode());

            // 根据存在的税收分类编码补全或修改明细的项目简称
            if (StringUtils.isNotBlank(detail.getSphfwssflhbbm())) {
                LambdaQueryWrapper<VmsClassifyCode> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(VmsClassifyCode::getSphfwssflhbbm, detail.getSphfwssflhbbm());
                queryWrapper.eq(VmsClassifyCode::getDeptCode, tokenUser.getDeptCode());
                VmsClassifyCode vmsClassifyCode = vmsClassifyCodeService.getOne(queryWrapper);
                if (vmsClassifyCode != null) {
                    // 如果项目名称为空,使用乐企返回数据进行补全,如果不为空且需要补全,则进行补全
                    String spmc = detail.getXmmc();
                    StringBuilder stringBuilder = new StringBuilder();
                    if (StringUtils.isBlank(spmc)) {
                        spmc = stringBuilder.append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwfljc()).append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwmc()).toString();
                    } else if (StringUtil.checkXmmc(spmc, vmsClassifyCode.getSphfwfljc())) {
                        spmc = stringBuilder.append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwfljc()).append(CommonConstant.STRING_STAR).append(spmc).toString();
                    }
                    detail.setXmmc(spmc);
                }
            }

            detailList.add(detail);
        }
        // 不动产销售、不动产租赁，明细行数据补全
        if (StrUtil.equalsAny(base.getTdys(), CommonEnum.TDYS_05.getKey(), CommonEnum.TDYS_06.getKey())) {
            // 不动产销售、不动产租赁明细行和特定业务有且只有一行
            VmsManualDetail vmsManualDetail = detailList.get(0);
            VmsManualTdywDto vmsManualTdywDto = tdywDtoList.get(0);
            if (StringUtils.isNotBlank(vmsManualTdywDto.getCqzsbh())) {
                vmsManualDetail.setGgxh(vmsManualTdywDto.getCqzsbh());
            }
            if (StringUtils.isNotBlank(vmsManualTdywDto.getMjdw())) {
                vmsManualDetail.setDw(vmsManualTdywDto.getMjdw());
            }
        }
        log.info("{}更新手工开票发票明细信息", LOG_MSG);
        vmsManualDetailService.saveBatch(detailList);

        // 更新非必填字段扩展信息
        if (extendDto != null) {
            VmsManualExtend extend = new VmsManualExtend();
            BeanUtils.copyBeanProp(extend, extendDto);
            extend.setBaseId(base.getId());
            log.info("{}更新手工开票非必填字段扩展信息", LOG_MSG);
            vmsManualExtendService.saveOrUpdate(extend);
        }

        // 更新附加要素信息，先删除原信息，在插入新信息
        if (CollectionUtil.isNotEmpty(addDtoList)) {
            LambdaQueryWrapper<VmsManualAdd> addQueryWrapper = new LambdaQueryWrapper<>();
            addQueryWrapper.eq(VmsManualAdd::getBaseId, base.getId());
            vmsManualAddService.remove(addQueryWrapper);

            List<VmsManualAdd> addList = new ArrayList<>();
            for (VmsManualAddDto vmsManualAddDto : addDtoList) {
                VmsManualAdd add = new VmsManualAdd();
                BeanUtils.copyBeanProp(add, vmsManualAddDto);
                add.setId(null);
                add.setBaseId(base.getId());

                addList.add(add);
            }
            log.info("{}更新手工开票附加要素信息", LOG_MSG);
            vmsManualAddService.saveBatch(addList);
        }

        // 更新特定业务信息
        if (CollectionUtil.isNotEmpty(tdywDtoList)) {
            if (CommonEnum.TDYS_05.getKey().equals(baseDto.getTdys())
                    || CommonEnum.TDYS_06.getKey().equals(baseDto.getTdys())
                    || CommonEnum.TDYS_09.getKey().equals(baseDto.getTdys())) {
                // 先删除原信息，在插入新信息
                LambdaQueryWrapper<VmsManualTdyw> tdywQuery = new LambdaQueryWrapper<>();
                tdywQuery.eq(VmsManualTdyw::getBaseId, base.getId());
                vmsManualTdywService.remove(tdywQuery);

                for (VmsManualTdywDto tdywDto : tdywDtoList) {
                    VmsManualTdyw tdyw = new VmsManualTdyw();
                    BeanUtils.copyBeanProp(tdyw, tdywDto);
                    tdyw.setTdywId(null);
                    tdyw.setBaseId(base.getId());
                    log.info("{}更新手工开票特定业务信息", LOG_MSG);
                    vmsManualTdywService.save(tdyw);

                    // 不动产销售服务发票，多方共同购买处理
                    if (CommonEnum.TDYS_05.getKey().equals(baseDto.getTdys())
                            && CommonConstant.STR_Y.equals(tdywDto.getDfgtgmbz())) {
                        // 先删除原信息，在插入新信息
                        LambdaQueryWrapper<VmsManualTdywItem> tdywItemQuery = new LambdaQueryWrapper<>();
                        tdywItemQuery.eq(VmsManualTdywItem::getTdywId, tdywDto.getTdywId());
                        vmsManualTdywItemService.remove(tdywItemQuery);

                        List<VmsManualTdywItemDto> gtgmfList = tdywDto.getTdywItemList();
                        List<VmsManualTdywItem> tdywItemList = BeanUtils.copyListProperties(gtgmfList, VmsManualTdywItem::new, (s, t) -> {
                            t.setId(null);
                            t.setTdywId(tdyw.getTdywId());
                        });
                        log.info("{}更新手工开票特定业务附加信息", LOG_MSG);
                        vmsManualTdywItemService.saveBatch(tdywItemList);
                    }
                }
            }
        }

        // 更新差额扣除信息，先删除原信息，在插入新信息
        if (CollectionUtil.isNotEmpty(cekcDtoList)) {
            if (CommonEnum.CEZS_02.getKey().equals(baseDto.getCezslxdm())) {
                LambdaQueryWrapper<VmsManualCekc> cekcQueryWrapper = new LambdaQueryWrapper<>();
                cekcQueryWrapper.eq(VmsManualCekc::getBaseId, base.getId());
                vmsManualCekcService.remove(cekcQueryWrapper);

                List<VmsManualCekc> cekcList = new ArrayList<>();
                for (int i = 0; i < cekcDtoList.size(); i++) {
                    VmsManualCekcDto vmsManualCekcDto = cekcDtoList.get(i);
                    VmsManualCekc vmsManualCekc = new VmsManualCekc();
                    BeanUtils.copyBeanProp(vmsManualCekc, vmsManualCekcDto);
                    vmsManualCekc.setId(null);
                    vmsManualCekc.setXh((long) (i + 1));
                    vmsManualCekc.setBaseId(base.getId());

                    cekcList.add(vmsManualCekc);
                }
                log.info("{}更新手工开票差额扣除信息", LOG_MSG);
                vmsManualCekcService.saveBatch(cekcList);
            }
        }

        return Result.OK();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> deleteInvoice(Long baseId) {

        // 查看发票主表数据
        LambdaQueryWrapper<VmsManualBase> baseQueryWrapper = new LambdaQueryWrapper<>();
        baseQueryWrapper.eq(VmsManualBase::getId, baseId);
        VmsManualBase base = this.getOne(baseQueryWrapper);
        if (base == null) {
            return Result.ERROR(ResponseEnum.INVOICE_NOT_FIND_ERROR);
        }

        // 删除发票主信息
        this.removeById(base.getId());

        // 删除发票明细信息
        LambdaQueryWrapper<VmsManualDetail> detailQueryWrapper = new LambdaQueryWrapper<>();
        detailQueryWrapper.eq(VmsManualDetail::getBaseId, base.getId());
        vmsManualDetailService.remove(detailQueryWrapper);

        // 删除非必填字段扩展信息
        LambdaQueryWrapper<VmsManualExtend> extendQueryWrapper = new LambdaQueryWrapper<>();
        extendQueryWrapper.eq(VmsManualExtend::getBaseId, base.getId());
        vmsManualExtendService.remove(extendQueryWrapper);

        // 删除附加要素信息
        LambdaQueryWrapper<VmsManualAdd> addQueryWrapper = new LambdaQueryWrapper<>();
        addQueryWrapper.eq(VmsManualAdd::getBaseId, base.getId());
        vmsManualAddService.remove(addQueryWrapper);

        // 删除特定业务信息
        if (CommonEnum.TDYS_05.getKey().equals(base.getTdys())
                || CommonEnum.TDYS_06.getKey().equals(base.getTdys())
                || CommonEnum.TDYS_09.getKey().equals(base.getTdys())) {
            LambdaQueryWrapper<VmsManualTdyw> tdywQueryWrapper = new LambdaQueryWrapper<>();
            tdywQueryWrapper.eq(VmsManualTdyw::getBaseId, base.getId());
            List<VmsManualTdyw> tdywList = vmsManualTdywService.list(tdywQueryWrapper);
            vmsManualTdywService.remove(tdywQueryWrapper);

            // 不动产销售服务发票，多方共同购买，删除特定业务附加信息
            if (CommonEnum.TDYS_05.getKey().equals(base.getTdys())
                    && CollectionUtil.isNotEmpty(tdywList) && tdywList.size() == 1
                    && CommonConstant.STR_Y.equals(tdywList.get(0).getDfgtgmbz())) {
                LambdaQueryWrapper<VmsManualTdywItem> tdywItemQuery = new LambdaQueryWrapper<>();
                tdywItemQuery.eq(VmsManualTdywItem::getTdywId, tdywList.get(0).getTdywId());
                vmsManualTdywItemService.remove(tdywItemQuery);
            }
        }

        // 删除差额扣除信息
        if (CommonEnum.CEZS_02.getKey().equals(base.getCezslxdm())) {
            LambdaQueryWrapper<VmsManualCekc> cekcQueryWrapper = new LambdaQueryWrapper<>();
            cekcQueryWrapper.eq(VmsManualCekc::getBaseId, base.getId());
            vmsManualCekcService.remove(cekcQueryWrapper);
        }

        return Result.OK();
    }

    @Override
    public void downloadExcel(HttpServletResponse response) {
        try {
            // 获取文件的路径 application/vnd.ms-excel
            String rootPath = "download/vmsManualInvoice.xlsx";
            InputStream fis = Thread.currentThread().getContextClassLoader().getResourceAsStream(rootPath);
            if (fis == null) {
                log.error("{}模板下载异常,读取不到文件", LOG_MSG);
                throw new BusinessException(ResponseEnum.BUSINESS_EXCEL_TEMPLATE_ERROR);
            }
            XSSFWorkbook workbook = new XSSFWorkbook(fis);
            // 通知类型
            response.reset();
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            String finalFileName = "手工开票导入模板";
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(finalFileName, "UTF8") + ".xlsx");
            workbook.write(response.getOutputStream());
            log.info("{}手工开票导入模板下载成功", LOG_MSG);
        } catch (Exception e) {
            log.error("{}模板下载异常", LOG_MSG, e);
            throw new BusinessException(ResponseEnum.BUSINESS_EXCEL_TEMPLATE_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> readAndSaveExcel(MultipartFile file, String fppz, Long applyId, TokenUser tokenUser) {
        InputStream inputStream;
        try {
            if (StringUtils.isBlank(fppz)) {
                return Result.ERROR(ResponseEnum.FPPZ_EMPTY_ERROR);
            }
            if (applyId == null || applyId == 0) {
                return Result.ERROR(ResponseEnum.APPLY_ID_EMPTY_ERROR);
            }
            inputStream = file.getInputStream();
            byte[] bytes = cloneInputStream(inputStream);

            // 读取手工开票基础信息
            ExcelListener<VmsManualBaseExcel> excelListener1 = new ExcelListener<>();
            InputStream inputStream1 = new ByteArrayInputStream(bytes);
            EasyExcel.read(inputStream1, VmsManualBaseExcel.class, excelListener1).headRowNumber(3).sheet(0).doRead();
            // 获取手工开票基础信息
            List<VmsManualBaseExcel> rows1 = excelListener1.getRows();
            if (CollectionUtil.isEmpty(rows1)) {
                return Result.ERROR(ResponseEnum.BUSINESS_EXCEL_VERIFY_ERROR);
            }

            // 读取手工开票次要信息
            ExcelListener<VmsManualExtendExcel> excelListener2 = new ExcelListener<>();
            InputStream inputStream2 = new ByteArrayInputStream(bytes);
            EasyExcel.read(inputStream2, VmsManualExtendExcel.class, excelListener2).headRowNumber(3).sheet(1).doRead();
            // 获取手工开票次要信息
            List<VmsManualExtendExcel> rows2 = excelListener2.getRows();

            // 读取手工开票明细信息
            ExcelListener<VmsManualDetailExcel> excelListener3 = new ExcelListener<>();
            InputStream inputStream3 = new ByteArrayInputStream(bytes);
            EasyExcel.read(inputStream3, VmsManualDetailExcel.class, excelListener3).headRowNumber(3).sheet(2).doRead();
            // 获取手工开票明细信息
            List<VmsManualDetailExcel> rows3 = excelListener3.getRows();
            if (CollectionUtil.isEmpty(rows3)) {
                return Result.ERROR(ResponseEnum.BUSINESS_EXCEL_EMPTY2_ERROR);
            }

            // 读取手工开票特定业务信息
            ExcelListener<VmsManualTdywExcel> excelListener4 = new ExcelListener<>();
            InputStream inputStream4 = new ByteArrayInputStream(bytes);
            EasyExcel.read(inputStream4, VmsManualTdywExcel.class, excelListener4).headRowNumber(3).sheet(3).doRead();
            // 获取手工开票特定业务信息
            List<VmsManualTdywExcel> rows4 = excelListener4.getRows();

            log.info("手工开票基础信息数据:{}", JSONObject.toJSONString(rows1));
            log.info("手工开票次要信息数据:{}", JSONObject.toJSONString(rows2));
            log.info("手工开票明细信息数据:{}", JSONObject.toJSONString(rows3));
            log.info("手工开票特定业务信息:{}", JSONObject.toJSONString(rows4));

            // 参数必填项、数据合法性校验
            List<String> errMsgList = checkExcelData(rows1, rows2, rows3, rows4);
            if (CollectionUtil.isNotEmpty(errMsgList)) {
                log.error("{}Excel导入数据合法性校验失败：{}", LOG_MSG, JSONObject.toJSONString(errMsgList));
                return Result.ERROR(ResponseEnum.BUSINESS_EXCEL_VERIFY_ERROR, errMsgList);
            }

            // 将key：value固定格式进行转换
            fixedFormalConvert(rows1, rows2, rows3, rows4);

            // 获取需要自动补全的信息（销售方信息、开票人、区域代码）
            Result<VmsManualDefaultVo> baseInfoResult = getBaseInfo(tokenUser);
            log.info("{}获取需要自动补全的信息：{}", LOG_MSG, JSONObject.toJSONString(baseInfoResult));
            VmsManualDefaultVo baseDefault = baseInfoResult.getData();

            List<VmsManualInvoice> invoiceList = new ArrayList<>();
            for (VmsManualBaseExcel baseExcel : rows1) {
                VmsManualInvoice invoice = new VmsManualInvoice();
                // 1.发票主信息
                VmsManualBase base = new VmsManualBase();
                BeanUtils.copyBeanProp(base, baseExcel);
                // 补全审批流id、发票票种、金额模式、销售方信息、开票人、机构编码、创建时间
                base.setApplyId(applyId);
                base.setFppz(fppz);
                base.setJems(CommonConstant.STR_01);
                base.setXsfmc(baseDefault.getXsfmc());
                base.setXsfnsrsbh(baseDefault.getXsfnsrsbh());
                base.setKpr(baseDefault.getKpr());
                base.setQydjid(tokenUser.getDeptCode());
                base.setCreatTime(new Date());
                base.setCreatBy(tokenUser.getUserCode());
                base.setUpdateTime(new Date());
                base.setUpdateBy(tokenUser.getUserCode());

                invoice.setVmsManualBase(base);

                List<VmsManualExtendExcel> extendExcelList = rows2.stream().filter(a -> baseExcel.getXh().equals(a.getXh())).collect(Collectors.toList());
                // 发票非必填字段扩展信息不为空
                if (CollectionUtil.isNotEmpty(extendExcelList)) {
                    // 2.发票非必填字段扩展信息
                    VmsManualExtendExcel extendExcel = extendExcelList.get(0);
                    VmsManualExtend extend = new VmsManualExtend();
                    BeanUtils.copyBeanProp(extend, extendExcel);
                    // 补全销售方信息
                    extend.setXsfdz(baseDefault.getXsfdz());
                    extend.setXsfdh(baseDefault.getXsfdh());
                    extend.setXsfkhh(baseDefault.getXsfkhh());
                    extend.setXsfzh(baseDefault.getXsfzh());
                    extend.setQydm(baseDefault.getQydm());
                    // 购买方自然人标志
                    extend.setGmfzrrbz(baseExcel.getGmfzrrbz());
                    invoice.setVmsManualExtend(extend);

                    List<VmsManualAdd> addList = new ArrayList<>();
                    for (VmsManualExtendExcel list : extendExcelList) {
                        if (StringUtils.isNotBlank(list.getFjysmc())) {
                            VmsManualAdd add = new VmsManualAdd();
                            // 补全附加要素信息
                            add.setFjysmc(list.getFjysmc());
                            add.setFjyslx(list.getFjyslx());
                            add.setFjysz(list.getFjysz());

                            addList.add(add);
                        }
                    }

                    // 3.附加要素信息
                    if (CollectionUtil.isNotEmpty(addList)) {
                        invoice.setVmsManualAddList(addList);
                    }
                } else {
                    // 发票非必填字段扩展信息为空
                    VmsManualExtend extend = new VmsManualExtend();
                    // 补全销售方信息
                    extend.setXsfdz(baseDefault.getXsfdz());
                    extend.setXsfdh(baseDefault.getXsfdh());
                    extend.setXsfkhh(baseDefault.getXsfkhh());
                    extend.setXsfzh(baseDefault.getXsfzh());
                    extend.setQydm(baseDefault.getQydm());
                    // 购买方自然人标志
                    extend.setGmfzrrbz(baseExcel.getGmfzrrbz());
                    invoice.setVmsManualExtend(extend);
                }

                // 4.发票明细信息
                List<VmsManualDetailExcel> detailExcelList = rows3.stream().filter(a -> baseExcel.getXh().equals(a.getXh())).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(detailExcelList)) {
                    List<VmsManualDetail> detailList = new ArrayList<>();
                    for (int i = 0; i < detailExcelList.size(); i++) {
                        VmsManualDetailExcel detailExcel = detailExcelList.get(i);
                        VmsManualDetail detail = new VmsManualDetail();
                        BeanUtils.copyBeanProp(detail, detailExcel);
                        // 补全明细序号
                        detail.setMxxh((long) (i + 1));
                        // 发票行性质，为空则默认为正常行
                        if (StringUtils.isBlank(detailExcel.getFphxz())) {
                            detail.setFphxz(CommonEnum.FPHXZ_00.getKey());
                        }
                        // 金额模式处理
                        if (CommonConstant.STR_02.equals(base.getJems())) {
                            detail.setHsdj(detail.getDj());
                        }
                        detail.setCreatTime(new Date());
                        detail.setCreatBy(tokenUser.getUserCode());

                        detailList.add(detail);
                    }
                    invoice.setVmsManualDetailList(detailList);

                    BigDecimal hjje = BigDecimal.ZERO;
                    BigDecimal hjse = BigDecimal.ZERO;
                    // 合计金额、合计税额计算
                    for (VmsManualDetail detail : detailList) {
                        hjje = hjje.add(detail.getJe());
                        hjse = hjse.add(detail.getSe());
                    }
                    // 补全合计金额、合计税额
                    base.setHjje(hjje);
                    base.setHjse(hjse);
                    base.setJshj(hjje.add(hjse));
                }

                // 5.发票特定业务信息
                List<VmsManualTdywExcel> tdywExcelList = rows4.stream().filter(a -> baseExcel.getXh().equals(a.getXh())).collect(Collectors.toList());
                // 目前只支持不动产销售、不动产租赁、旅客运输
                if (CollectionUtil.isNotEmpty(tdywExcelList)) {
                    // 不动产销售特定业务处理
                    if (CommonEnum.TDYS_05.getKey().equals(baseExcel.getTdys())) {
                        VmsManualTdywExcel tdywExcel = tdywExcelList.get(0);
                        VmsManualTdyw tdyw = new VmsManualTdyw();
                        BeanUtils.copyBeanProp(tdyw, tdywExcel);

                        // 共同购买方处理
                        if (CommonConstant.STR_Y.equals(tdywExcel.getDfgtgmbz())) {
                            List<VmsManualTdywItem> tdywItemList = new ArrayList<>();
                            for (VmsManualTdywExcel tdywExcel1 : tdywExcelList) {
                                VmsManualTdywItem tdywItem = new VmsManualTdywItem();
                                tdywItem.setGtgmf(tdywExcel1.getGtgmf());
                                tdywItem.setZjlx(tdywExcel1.getZjlx());
                                tdywItem.setZjhm(tdywExcel1.getZjhm());
                                tdywItemList.add(tdywItem);
                            }
                            tdyw.setTdywItemList(tdywItemList);
                        }

                        invoice.setVmsManualTdywList(Collections.singletonList(tdyw));
                    }

                    // 不动产租赁特定业务处理
                    if (CommonEnum.TDYS_06.getKey().equals(baseExcel.getTdys())) {
                        VmsManualTdywExcel tdywExcel = tdywExcelList.get(0);
                        VmsManualTdyw tdyw = new VmsManualTdyw();
                        BeanUtils.copyBeanProp(tdyw, tdywExcel);

                        invoice.setVmsManualTdywList(Collections.singletonList(tdyw));
                    }

                    // 旅客运输特定业务处理
                    if (CommonEnum.TDYS_09.getKey().equals(baseExcel.getTdys())) {
                        List<VmsManualTdyw> tdywList = new ArrayList<>();
                        for (VmsManualTdywExcel tdywExcel : tdywExcelList) {
                            VmsManualTdyw tdyw = new VmsManualTdyw();
                            BeanUtils.copyBeanProp(tdyw, tdywExcel);

                            tdywList.add(tdyw);
                        }
                        invoice.setVmsManualTdywList(tdywList);
                    }
                }

                invoiceList.add(invoice);
            }

            // 数据转换并进行业务逻辑校验
            List<VmsFullOutInvoiceInfoDto> vmsFullOutInvoiceInfoDtoList = convertToVmsFullOutInvoiceInfoDtoList(invoiceList);
            List<ErrorVerifyVo> errorVerifyVoList = checkDataService.checkDataBusiness(vmsFullOutInvoiceInfoDtoList,
                    tokenUser.getDeptCode(), CommonEnum.CHECK_SOURCE_1.getKey());
            if (CollectionUtil.isNotEmpty(errorVerifyVoList)) {
                log.error("{}Excel导入业务逻辑校验失败，错误信息：{}", LOG_MSG, JSONObject.toJSONString(errorVerifyVoList));
                return Result.ERROR(ResponseEnum.ISSUE_INVOICE_VERIFY_ERROR, errorVerifyVoList);
            }

            for (VmsManualInvoice invoice : invoiceList) {
                // 价税分离，统一将明细转换为不含税金额、税额
                invoice = priceTaxSeparationService.priceTaxSeparation(invoice);
                log.info("{}本次Excel导入数据价税分离后：{}", LOG_MSG, JSONObject.toJSONString(invoice));

                // 保存发票数据
                VmsManualBase vmsManualBase = invoice.getVmsManualBase();
                List<VmsManualDetail> vmsManualDetailList = invoice.getVmsManualDetailList();
                VmsManualExtend vmsManualExtend = invoice.getVmsManualExtend();
                List<VmsManualAdd> vmsManualAddList = invoice.getVmsManualAddList();
                List<VmsManualTdyw> vmsManualTdywList = invoice.getVmsManualTdywList();

                log.info("{}保存Excel发票主信息", LOG_MSG);
                this.save(vmsManualBase);

                for (VmsManualDetail detail : vmsManualDetailList) {
                    // 手工开票主表主键ID赋值
                    detail.setBaseId(vmsManualBase.getId());
                    /*
                        根据企业商品及服务编码补全数据：
                        1.若税收分类编码、项目名称、计量单位、计税方法、征税项目、优惠政策标识为空，则使用系统企业商品及服务编码对用的数据自动补全；
                        2.若税收分类编码、项目名称、计量单位、计税方法、征税项目、优惠政策标识不为空，则以Excel填写的数据为准
                    */
                    LambdaQueryWrapper<VmsEpsInformation> query = new LambdaQueryWrapper<>();
                    query.eq(VmsEpsInformation::getEpsCode, detail.getCpbm())
                            // 下边代码加上括号
                            .and(m -> m.nested(n -> n.eq(VmsEpsInformation:: getApplication, CommonConstant.STR_02)
                                    .like(VmsEpsInformation:: getJyjg, tokenUser.getDeptCode()))
                                    .or()
                                    .eq(VmsEpsInformation:: getApplication, CommonConstant.STR_01));
                    VmsEpsInformation vmsEpsInformation = vmsEpsInformationService.getOne(query);
                    if (vmsEpsInformation != null) {
                        if (StringUtils.isBlank(detail.getSphfwssflhbbm())) {
                            detail.setSphfwssflhbbm(vmsEpsInformation.getGstcmCode());
                        }
                        if (StringUtils.isBlank(detail.getXmmc())) {
                            detail.setXmmc(vmsEpsInformation.getEpsName());
                        }
                        if (StringUtils.isBlank(detail.getDw())) {
                            detail.setDw(dictTranslate.translate(DictConstant.VMS_JLDW, vmsEpsInformation.getJldw()));
                        }
                        if (StringUtils.isBlank(detail.getJsff())) {
                            detail.setJsff(vmsEpsInformation.getJsff());
                        }
                        if (StringUtils.isBlank(detail.getZsxm())) {
                            detail.setZsxm(vmsEpsInformation.getZsxm());
                        }
                        if (StringUtils.isBlank(detail.getYhzcbs())) {
                            detail.setYhzcbs(vmsEpsInformation.getYhzcbs());
                        }
                    }

                    // 校验税收分类编码当前机构是否可以使用，并根据存在的税收分类编码补全或修改明细的项目简称
                    if (StringUtils.isNotBlank(detail.getSphfwssflhbbm())) {
                        LambdaQueryWrapper<VmsClassifyCode> queryWrapper = new LambdaQueryWrapper<>();
                        queryWrapper.eq(VmsClassifyCode::getSphfwssflhbbm, detail.getSphfwssflhbbm());
                        queryWrapper.eq(VmsClassifyCode::getDeptCode, tokenUser.getDeptCode());
                        VmsClassifyCode vmsClassifyCode = vmsClassifyCodeService.getOne(queryWrapper);
                        if (vmsClassifyCode != null) {
                            // 如果项目名称为空,使用乐企返回数据进行补全,如果不为空且需要补全,则进行补全
                            String spmc = detail.getXmmc();
                            StringBuilder stringBuilder = new StringBuilder();
                            if (StringUtils.isBlank(spmc)) {
                                spmc = stringBuilder.append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwfljc()).append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwmc()).toString();
                            } else if (StringUtil.checkXmmc(spmc, vmsClassifyCode.getSphfwfljc())) {
                                spmc = stringBuilder.append(CommonConstant.STRING_STAR).append(vmsClassifyCode.getSphfwfljc()).append(CommonConstant.STRING_STAR).append(spmc).toString();
                            }
                            detail.setXmmc(spmc);
                        }
                    }
                }

                // 不动产销售、不动产租赁，明细行数据补全
                if (StrUtil.equalsAny(vmsManualBase.getTdys(), CommonEnum.TDYS_05.getKey(), CommonEnum.TDYS_06.getKey())) {
                    // 不动产销售、不动产租赁明细行和特定业务有且只有一行
                    VmsManualDetail vmsManualDetail = vmsManualDetailList.get(0);
                    VmsManualTdyw vmsManualTdyw = vmsManualTdywList.get(0);
                    if (StringUtils.isNotBlank(vmsManualTdyw.getCqzsbh())) {
                        vmsManualDetail.setGgxh(vmsManualTdyw.getCqzsbh());
                    }
                    if (StringUtils.isNotBlank(vmsManualTdyw.getMjdw())) {
                        vmsManualDetail.setDw(vmsManualTdyw.getMjdw());
                    }
                }
                log.info("{}保存Excel发票明细信息", LOG_MSG);
                vmsManualDetailService.saveBatch(vmsManualDetailList);

                if (vmsManualExtend != null) {
                    vmsManualExtend.setBaseId(vmsManualBase.getId());
                    log.info("{}保存Excel发票非必填扩展信息", LOG_MSG);
                    vmsManualExtendService.save(vmsManualExtend);
                }

                if (CollectionUtil.isNotEmpty(vmsManualAddList)) {
                    vmsManualAddList = vmsManualAddList.stream().peek(VmsManualAdd -> {
                        VmsManualAdd.setBaseId(vmsManualBase.getId());
                    }).collect(Collectors.toList());
                    log.info("{}保存Excel发票附加要素信息", LOG_MSG);
                    vmsManualAddService.saveBatch(vmsManualAddList);
                }

                // 保存特定业务信息
                if (CollectionUtil.isNotEmpty(vmsManualTdywList)) {
                    // 不动产销售服务发票、不动产租赁服务发票 特定业务信息只有一条
                    // 旅客运输服务发票 特定业务信息可以有多条
                    if (CommonEnum.TDYS_05.getKey().equals(vmsManualBase.getTdys())
                            || CommonEnum.TDYS_06.getKey().equals(vmsManualBase.getTdys())
                            || CommonEnum.TDYS_09.getKey().equals(vmsManualBase.getTdys())) {
                        for (VmsManualTdyw vmsManualTdyw : vmsManualTdywList) {
                            vmsManualTdyw.setBaseId(vmsManualBase.getId());
                            log.info("{}保存Excel发票特定业务信息", LOG_MSG);
                            vmsManualTdywService.save(vmsManualTdyw);

                            // 不动产销售服务发票，多方共同购买处理
                            if (CommonEnum.TDYS_05.getKey().equals(vmsManualBase.getTdys())
                                    && CommonConstant.STR_Y.equals(vmsManualTdyw.getDfgtgmbz())) {
                                List<VmsManualTdywItem> tdywItemList = vmsManualTdyw.getTdywItemList();
                                for (VmsManualTdywItem tdywItem : tdywItemList) {
                                    tdywItem.setTdywId(vmsManualTdyw.getTdywId());
                                }
                                log.info("{}保存Excel发票特定业务附加信息", LOG_MSG);
                                vmsManualTdywItemService.saveBatch(tdywItemList);
                            }
                        }
                    }
                }
            }

            return Result.OK();
        } catch (BusinessException e) {
            log.error("{}Excel数据校验异常，code：{}，msg：{}", LOG_MSG, e.getCode(), e.getMsg());
            throw new BusinessException(e.getCode(), e.getMsg());
        } catch (Exception e) {
            log.error("{}Excel导入并保存异常", LOG_MSG, e);
            throw new BusinessException(ResponseEnum.BUSINESS_EXCEL_READ_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> manualInvoice(Long applyId, TokenUser tokenUser) {
        log.info("{}手工开票流程进行开票，审批流id：{}，操作人：{}", LOG_MSG, applyId, tokenUser.getUserName());
        List<VmsFullOutInvoiceInfoDto> invoiceDtoList = new ArrayList<>();
        // 根据审批流id获取发票信息
        LambdaQueryWrapper<VmsManualBase> baseQueryWrapper = new LambdaQueryWrapper<>();
        baseQueryWrapper.eq(VmsManualBase::getApplyId, applyId);
        baseQueryWrapper.orderByAsc(VmsManualBase::getId);
        List<VmsManualBase> baseList = this.list(baseQueryWrapper);
        for (VmsManualBase base : baseList) {
            VmsFullOutInvoiceInfoDto invoiceDto = new VmsFullOutInvoiceInfoDto();

            // 转换为数电发票主信息
            VmsFullOutInvoiceDetails invoice = convertToFullOutInvoiceDetails(base);
            invoiceDto.setVmsFullOutInvoiceDetails(invoice);

            // 转换为数电发票明细信息
            LambdaQueryWrapper<VmsManualDetail> detailQueryWrapper = new LambdaQueryWrapper<>();
            detailQueryWrapper.eq(VmsManualDetail::getBaseId, base.getId());
            detailQueryWrapper.orderByAsc(VmsManualDetail::getMxxh);
            List<VmsManualDetail> detailList = vmsManualDetailService.list(detailQueryWrapper);
            List<VmsFullOutInvoiceItems> invoiceItemList = new ArrayList<>();
            for (VmsManualDetail detail : detailList) {
                VmsFullOutInvoiceItems fullOutInvoiceItems = new VmsFullOutInvoiceItems();
                BeanUtils.copyProperties(detail, fullOutInvoiceItems);
                fullOutInvoiceItems.setCreatBy(tokenUser.getUserCode());
                fullOutInvoiceItems.setCreatTime(new Date());

                invoiceItemList.add(fullOutInvoiceItems);
            }
            invoiceDto.setVmsFullOutInvoiceItemsList(invoiceItemList);

            // 转换为数电非必填字段扩展信息
            LambdaQueryWrapper<VmsManualExtend> extendQueryWrapper = new LambdaQueryWrapper<>();
            extendQueryWrapper.eq(VmsManualExtend::getBaseId, base.getId());
            VmsManualExtend extend = vmsManualExtendService.getOne(extendQueryWrapper);
            if (ObjectUtil.isNotNull(extend)) {
                VmsFullOutInvoiceItemsExp invoiceItemsExp = new VmsFullOutInvoiceItemsExp();
                BeanUtils.copyProperties(extend, invoiceItemsExp);
                invoiceDto.setVmsFullOutInvoiceItemsExp(invoiceItemsExp);
            }

            // 转换为数电发票附加要素信息
            LambdaQueryWrapper<VmsManualAdd> addQueryWrapper = new LambdaQueryWrapper<>();
            addQueryWrapper.eq(VmsManualAdd::getBaseId, base.getId());
            addQueryWrapper.orderByAsc(VmsManualAdd::getId);
            List<VmsManualAdd> addList = vmsManualAddService.list(addQueryWrapper);
            if (CollectionUtil.isNotEmpty(addList)) {
                List<VmsFullOutInvoiceItemsAdd> invoiceItemsAddList = new ArrayList<>();
                for (VmsManualAdd add : addList) {
                    VmsFullOutInvoiceItemsAdd invoiceItemsAdd = new VmsFullOutInvoiceItemsAdd();
                    BeanUtils.copyProperties(add, invoiceItemsAdd);

                    invoiceItemsAddList.add(invoiceItemsAdd);
                }
                invoiceDto.setVmsFullOutInvoiceItemsAddList(invoiceItemsAddList);
            }

            // 转换为数电发票特定业务信息
            if (StrUtil.equalsAny(base.getTdys(), CommonEnum.TDYS_05.getKey(), CommonEnum.TDYS_06.getKey(), CommonEnum.TDYS_09.getKey())) {
                LambdaQueryWrapper<VmsManualTdyw> tdywQueryWrapper = new LambdaQueryWrapper<>();
                tdywQueryWrapper.eq(VmsManualTdyw::getBaseId, base.getId());
                tdywQueryWrapper.orderByAsc(VmsManualTdyw::getTdywId);
                List<VmsManualTdyw> vmsManualTdywList = vmsManualTdywService.list(tdywQueryWrapper);

                if (CollectionUtil.isNotEmpty(vmsManualTdywList)) {
                    List<VmsFullOutInvoiceTdyw> invoiceTdywList = new ArrayList<>();
                    for (VmsManualTdyw vmsManualTdyw : vmsManualTdywList) {
                        VmsFullOutInvoiceTdyw invoiceTdyw = new VmsFullOutInvoiceTdyw();
                        BeanUtils.copyProperties(vmsManualTdyw, invoiceTdyw);

                        // 不动产销售 共同购买方处理
                        if (CommonEnum.TDYS_05.getKey().equals(base.getTdys())
                                && CommonConstant.STR_Y.equals(vmsManualTdyw.getDfgtgmbz())) {
                            LambdaQueryWrapper<VmsManualTdywItem> itemQuery = new LambdaQueryWrapper<>();
                            itemQuery.eq(VmsManualTdywItem::getTdywId, vmsManualTdyw.getTdywId());
                            itemQuery.orderByAsc(VmsManualTdywItem::getId);
                            List<VmsManualTdywItem> tdywItemList = vmsManualTdywItemService.list(itemQuery);
                            List<VmsFullOutInvoiceTdywItem> invoiceTdywItemList = BeanUtils.copyListProperties(tdywItemList, VmsFullOutInvoiceTdywItem::new);
                            invoiceTdyw.setTdywItemList(invoiceTdywItemList);
                        }

                        invoiceTdywList.add(invoiceTdyw);
                    }
                    invoiceDto.setVmsFullOutInvoiceTdywList(invoiceTdywList);
                }
            }

            // 转换为数电发票差额扣除信息
            LambdaQueryWrapper<VmsManualCekc> cekcQueryWrapper = new LambdaQueryWrapper<>();
            cekcQueryWrapper.eq(VmsManualCekc::getBaseId, base.getId());
            cekcQueryWrapper.orderByAsc(VmsManualCekc::getId);
            List<VmsManualCekc> cekcList = vmsManualCekcService.list(cekcQueryWrapper);
            if (CollectionUtil.isNotEmpty(cekcList)) {
                List<VmsFullOutInvoiceCekc> invoiceCekcList = new ArrayList<>();
                for (VmsManualCekc cekc : cekcList) {
                    VmsFullOutInvoiceCekc invoiceCekc = new VmsFullOutInvoiceCekc();
                    BeanUtils.copyProperties(cekc, invoiceCekc);

                    invoiceCekcList.add(invoiceCekc);
                }
                invoiceDto.setVmsFullOutInvoiceCekcList(invoiceCekcList);
            }

            invoiceDtoList.add(invoiceDto);
        }

        // 调用开票接口进行开票
        Result<Object> result = issueInvoiceService.issueInvoice(invoiceDtoList, tokenUser);
        if (!ResponseEnum.SUCCESS.getCode().equals(result.getCode())) {
            if (result.getData() == null) {
                log.error("{}手工开票失败，错误原因：{}", LOG_MSG, result.getMessage());
            } else {
                log.error("{}手工开票失败，错误原因：{}", LOG_MSG, JSONObject.toJSONString(result.getData()));
            }
            return result;
        }

        return Result.OK();
    }

    /**
     * 将手工开票发票主信息转换为数电发票主信息
     * @param vmsManualBase 手工开票发票主信息
     * @return 数电发票主信息
     */
    private VmsFullOutInvoiceDetails convertToFullOutInvoiceDetails(VmsManualBase vmsManualBase) {
        VmsFullOutInvoiceDetails fullOutInvoiceDetails = new VmsFullOutInvoiceDetails();
        BeanUtils.copyProperties(vmsManualBase, fullOutInvoiceDetails);

        fullOutInvoiceDetails.setBaseId(vmsManualBase.getId());
        fullOutInvoiceDetails.setLzfpbz(CommonEnum.INVOICE_BLUE.getKey());
        fullOutInvoiceDetails.setKprq(new Date());
        fullOutInvoiceDetails.setSczt(CommonEnum.INVOICE_UPLOAD_STATUS_0.getKey());
        fullOutInvoiceDetails.setFpzt(CommonEnum.INVOICE_STATUS_0.getKey());
        fullOutInvoiceDetails.setSjly(CommonEnum.DATA_SOURCE_1.getKey());
        fullOutInvoiceDetails.setPpzt(CommonEnum.MATCHING_STATUS_0.getKey());
        fullOutInvoiceDetails.setSfbdc(CommonEnum.SFBDC_NO.getKey());
        if (CommonConstant.STR_02.equals(fullOutInvoiceDetails.getCezslxdm())) {
            fullOutInvoiceDetails.setZsfs(CommonConstant.STR_2);
        } else {
            fullOutInvoiceDetails.setZsfs(CommonConstant.STR_0);
        }
        fullOutInvoiceDetails.setKpzt(CommonEnum.KPZT_2.getKey());
        fullOutInvoiceDetails.setDelFlag(CommonEnum.DEL_STATUS_0.getKey());
        fullOutInvoiceDetails.setCreatTime(new Date());
        fullOutInvoiceDetails.setCreatBy(SecurityUtils.getUserCode());
        fullOutInvoiceDetails.setUpdateTime(new Date());
        fullOutInvoiceDetails.setUpdateBy(SecurityUtils.getUserCode());

        return fullOutInvoiceDetails;
    }

    /**
     * 将key：value固定格式进行转换
     * 取key值进行展示与入库
     */
    private void fixedFormalConvert(List<VmsManualBaseExcel> rows1, List<VmsManualExtendExcel> rows2,
                                    List<VmsManualDetailExcel> rows3, List<VmsManualTdywExcel> rows4) throws Exception {

        // 获取发票主信息所有使用固定格式的字段
        List<String> baseFields = CheckParamEnum.getFixedFormalConvertFields("VmsManualBaseExcel");
        // 转换发票主信息
        for (VmsManualBaseExcel vmsManualBaseExcel : rows1) {
            // 定义要遍历的类
            Class<?> clazz = vmsManualBaseExcel.getClass();
            // 遍历类的所有字段
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                // 获取字段名
                String name = field.getName();
                // 检查字段的类型是否是String且使用了固定格式
                if (field.getType() == String.class && baseFields.contains(name)) {
                    // 获取字段的值
                    String value = (String) field.get(vmsManualBaseExcel);
                    if (StringUtils.isNotBlank(value)) {
                        String[] split = value.split("：");
                        if (split.length == 2) {
                            // 取"："前的代码值
                            String newValue = split[0];
                            // 设置新的值
                            field.set(vmsManualBaseExcel, newValue);
                        }
                    }
                }
            }
        }

        // 获取发票非必填字段扩展信息所有使用固定格式的字段
        List<String> extendFields = CheckParamEnum.getFixedFormalConvertFields("VmsManualExtendExcel");
        // 转换发票非必填字段扩展信息
        for (VmsManualExtendExcel vmsManualExtendExcel : rows2) {
            // 定义要遍历的类
            Class<?> clazz = vmsManualExtendExcel.getClass();
            // 遍历类的所有字段
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                // 获取字段名
                String name = field.getName();
                // 检查字段的类型是否是String且使用了固定格式
                if (field.getType() == String.class && extendFields.contains(name)) {
                    // 获取字段的值
                    String value = (String) field.get(vmsManualExtendExcel);
                    if (StringUtils.isNotBlank(value)) {
                        String[] split = value.split("：");
                        if (split.length == 2) {
                            // 取"："前的代码值
                            String newValue = split[0];
                            // 设置新的值
                            field.set(vmsManualExtendExcel, newValue);
                        }
                    }
                }
            }
        }

        // 获取发票明细信息所有使用固定格式的字段
        List<String> detailFields = CheckParamEnum.getFixedFormalConvertFields("VmsManualDetailExcel");
        // 转换发票明细信息
        for (VmsManualDetailExcel vmsManualDetailExcel : rows3) {
            // 定义要遍历的类
            Class<?> clazz = vmsManualDetailExcel.getClass();
            // 遍历类的所有字段
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                // 获取字段名
                String name = field.getName();
                // 检查字段的类型是否是String且使用了固定格式
                if (field.getType() == String.class && detailFields.contains(name)) {
                    // 获取字段的值
                    String value = (String) field.get(vmsManualDetailExcel);
                    if (StringUtils.isNotBlank(value)) {
                        String[] split = value.split("：");
                        if (split.length == 2) {
                            // 取"："前的代码值
                            String newValue = split[0];
                            // 设置新的值
                            field.set(vmsManualDetailExcel, newValue);
                        }
                    }
                }
            }
        }

        // 获取发票特定业务信息所有使用固定格式的字段
        List<String> tdywFields = CheckParamEnum.getFixedFormalConvertFields("VmsManualTdywExcel");
        // 转换发票特定业务信息
        for (VmsManualTdywExcel vmsManualTdywExcel : rows4) {
            // 定义要遍历的类
            Class<?> clazz = vmsManualTdywExcel.getClass();
            // 遍历类的所有字段
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                // 获取字段名
                String name = field.getName();
                // 检查字段的类型是否是String且使用了固定格式
                if (field.getType() == String.class && tdywFields.contains(name)) {
                    // 获取字段的值
                    String value = (String) field.get(vmsManualTdywExcel);
                    if (StringUtils.isNotBlank(value)) {
                        String[] split = value.split("：");
                        if (split.length == 2) {
                            // 取"："前的代码值
                            String newValue = split[0];
                            // 设置新的值
                            field.set(vmsManualTdywExcel, newValue);
                        }
                    }
                }
            }
        }
    }

    /**
     * 校验纳税人基本信息和纳税人风险信息是否满足开票条件
     */
    private ResponseEnum checkEnterpriseInfoAndRisk(VmsEnterpriseInfo vmsEnterpriseInfo, VmsEnterpriseInfoRisk vmsEnterpriseInfoRisk) {
        /*
        如果纳税人识别号对应的“开票方纳税人状态”非“正常”或“报验中”，则弹窗提示：“当前机构的“开票方纳税人状态”非“正常”或“报验中”，不允许手工开票，请核实纳税人基本信息！”；
        如果纳税人识别号对应的“风险纳税人类型”为“Ⅰ类（高风险）纳税人”，则弹窗提示：“当前机构的“风险纳税人类型”为“Ⅰ类（高风险）纳税人”，不允许手工开票，请核实纳税人风险信息！”；
        纳税人识别号对应的“纳税人预警级别”为“红色预警”，则弹窗提示：“当前机构的“纳税人预警级别”为“红色预警”，不允许手工开票，请核实纳税人风险信息！”；
        纳税人识别号对应的“风险纳税人标志”为“Y（风险纳税人）”则弹窗提示：“当前机构的“风险纳税人标志”为“Y（风险纳税人）”，不允许手工开票，请核实纳税人风险信息！”。
        */

        if (vmsEnterpriseInfo == null || vmsEnterpriseInfo.getId() == null) {
            return ResponseEnum.BUSINESS_ENT_INFO_ERROR1;
        }

        if (vmsEnterpriseInfoRisk == null || vmsEnterpriseInfoRisk.getId() == null) {
            return ResponseEnum.BUSINESS_ENT_RISK_ERROR1;
        }

        if (!StrUtil.equalsAny(vmsEnterpriseInfo.getNsrztdm(), CommonEnum.ENTERPRISE_INFO_STATUS_03.getKey(), CommonEnum.ENTERPRISE_INFO_STATUS_09.getKey())) {
            return ResponseEnum.BUSINESS_ENT_INFO_ERROR2;
        }

        if (CommonEnum.RISK_TYPE_01.getKey().equals(vmsEnterpriseInfoRisk.getFxnsrlx())) {
            return ResponseEnum.BUSINESS_ENT_RISK_ERROR2;
        }

        if (CommonEnum.RISK_WARNING_LEVEL_01.getKey().equals(vmsEnterpriseInfoRisk.getNsryjjb())) {
            return ResponseEnum.BUSINESS_ENT_RISK_ERROR3;
        }

        if (CommonEnum.RISK_FLAG_Y.getKey().equals(vmsEnterpriseInfoRisk.getFxnsrbz())) {
            return ResponseEnum.BUSINESS_ENT_RISK_ERROR4;
        }

        return ResponseEnum.SUCCESS;
    }

    /**
     * 克隆InputStream
     */
    private static byte[] cloneInputStream(InputStream input) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = input.read(buffer)) > -1) {
                baos.write(buffer, 0, len);
            }
            baos.flush();
            baos.close();
            input.close();
            return baos.toByteArray();
        } catch (IOException e) {
            log.error("{}克隆InputStream异常", LOG_MSG, e);
            throw new BusinessException(ResponseEnum.BUSINESS_EXCEL_READ_ERROR);
        }
    }

    /**
     * 手工开具发票数据校验，如有错误则返回
     */
    private List<String> checkManualData(VmsManualInvoiceDto vmsManualInvoiceDto) {
        List<String> errMsgList = new ArrayList<>();

        VmsManualBaseDto vmsManualBaseDto = vmsManualInvoiceDto.getVmsManualBaseDto();
        VmsManualExtendDto vmsManualExtendDto = vmsManualInvoiceDto.getVmsManualExtendDto();
        List<VmsManualDetailDto> vmsManualDetailDtoList = vmsManualInvoiceDto.getVmsManualDetailDtoList();
        List<VmsManualAddDto> vmsManualAddDtoList = vmsManualInvoiceDto.getVmsManualAddDtoList();
        List<VmsManualTdywDto> vmsManualTdywDtoList = vmsManualInvoiceDto.getVmsManualTdywDtoList();
        List<VmsManualCekcDto> vmsManualCekcDtoList = vmsManualInvoiceDto.getVmsManualCekcDtoList();

        /**
         * 校验发票主信息
         */
        if (ObjectUtil.isNotEmpty(vmsManualBaseDto)) {

            String errMsg = "手工开票发票主信息：";

            // 参数校验
            String msg;
            boolean isError = false;

            // 发票票种
            msg = checkStringParam(vmsManualBaseDto.getFppz(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_FPPZ);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 差额征税类型代码
            msg = checkStringParam(vmsManualBaseDto.getCezslxdm(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_CEZSLXDM);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 金额模式
            msg = checkStringParam(vmsManualBaseDto.getJems(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_JEMS);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 特定要素
            msg = checkStringParam(vmsManualBaseDto.getTdys(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_TDYS);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 单号类型
            msg = checkStringParam(vmsManualBaseDto.getDhlx(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_DHLX);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 单号
            msg = checkStringParam(vmsManualBaseDto.getDh(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_DH);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 备注
            msg = checkStringParam(vmsManualBaseDto.getBz(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_BZ);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 购方名称
            msg = checkStringParam(vmsManualBaseDto.getGmfmc(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_GMFMC);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 购方纳税人识别号
            msg = checkStringParam(vmsManualBaseDto.getGmfnsrsbh(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_GMFNSRSBH);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 销售方名称
            msg = checkStringParam(vmsManualBaseDto.getXsfmc(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_XSFMC);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 销售方纳税人识别号
            msg = checkStringParam(vmsManualBaseDto.getXsfnsrsbh(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_XSFNSRSBH);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 合计金额
            msg = checkBigDecimalParam(vmsManualBaseDto.getHjje(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_HJJE);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 合计税额
            msg = checkBigDecimalParam(vmsManualBaseDto.getHjse(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_HJSE);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 价税合计
            msg = checkBigDecimalParam(vmsManualBaseDto.getJshj(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_JSHJ);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 开票人
            msg = checkStringParam(vmsManualBaseDto.getKpr(), CheckParamEnum.CHECK_VMSMANUALBASEDTO_KPR);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            if (isError) {
                if (errMsg.endsWith(CommonConstant.STRING_COMMA)) {
                    errMsg = errMsg.substring(0, errMsg.lastIndexOf(CommonConstant.STRING_COMMA));
                }
                errMsgList.add(errMsg);
            }
        }

        /**
         * 校验发票非必填扩展信息
         */
        if (ObjectUtil.isNotEmpty(vmsManualExtendDto)) {
            String errMsg = "手工开票发票非必填扩展信息：";

            // 参数校验
            String msg;
            boolean isError = false;

            // 增值税即征即退代码
            msg = checkStringParam(vmsManualExtendDto.getZzsjzjtdm(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_ZZSJZJTDM);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 收购发票类型代码
            msg = checkStringParam(vmsManualExtendDto.getSgfplxdm(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_SGFPLXDM);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 出口业务适用政策代码
            msg = checkStringParam(vmsManualExtendDto.getCkywsyzcdm(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_CKYWSYZCDM);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 购方地址
            msg = checkStringParam(vmsManualExtendDto.getGmfdz(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_GMFDZ);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 购方电话
            msg = checkStringParam(vmsManualExtendDto.getGmfdh(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_GMFDH);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 购方开户行
            msg = checkStringParam(vmsManualExtendDto.getGmfkhh(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_GMFKHH);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 购买方账号
            msg = checkStringParam(vmsManualExtendDto.getGmfzh(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_GMFZH);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 购买方经办人姓名
            msg = checkStringParam(vmsManualExtendDto.getGmfjbr(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_GMFJBR);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 购买方经办人证件号码
            msg = checkStringParam(vmsManualExtendDto.getJbrsfzjhm(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_JBRSFZJHM);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 购买方经办人联系电话
            msg = checkStringParam(vmsManualExtendDto.getGmfjbrlxdh(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_GMFJBRLXDH);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 购买方自然人标志
            msg = checkStringParam(vmsManualExtendDto.getGmfzrrbz(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_GMFZRRBZ);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 销售方地址
            msg = checkStringParam(vmsManualExtendDto.getXsfdz(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_XSFDZ);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 销售方电话
            msg = checkStringParam(vmsManualExtendDto.getXsfdh(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_XSFDH);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 销售方开户行
            msg = checkStringParam(vmsManualExtendDto.getXsfkhh(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_XSFKHH);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 销售方账号
            msg = checkStringParam(vmsManualExtendDto.getXsfzh(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_XSFZH);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 收款银行名称
            msg = checkStringParam(vmsManualExtendDto.getSkyhmc(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_SKYHMC);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 收款银行账号
            msg = checkStringParam(vmsManualExtendDto.getSkyhzh(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_SKYHZH);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 结算方式
            msg = checkStringParam(vmsManualExtendDto.getJsfs(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_JSFS);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 开票人证件类型
            msg = checkStringParam(vmsManualExtendDto.getKprzjlx(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_KPRZJLX);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 开票人证件号码
            msg = checkStringParam(vmsManualExtendDto.getKprzjhm(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_KPRZJHM);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 收款人
            msg = checkStringParam(vmsManualExtendDto.getSkrxm(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_SKRXM);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 复核人
            msg = checkStringParam(vmsManualExtendDto.getFhrxm(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_FHRXM);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 区域代码
            msg = checkStringParam(vmsManualExtendDto.getQydm(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_QYDM);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            // 应税行为发生地
            msg = checkStringParam(vmsManualExtendDto.getYsxwfsd(), CheckParamEnum.CHECK_VMSMANUALEXTENDDTO_YSXWFSD);
            if (StringUtils.isNotBlank(msg)) {
                errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                isError = true;
            }

            if (isError) {
                if (errMsg.endsWith(CommonConstant.STRING_COMMA)) {
                    errMsg = errMsg.substring(0, errMsg.lastIndexOf(CommonConstant.STRING_COMMA));
                }
                errMsgList.add(errMsg);
            }
        }

        /**
         * 校验发票明细信息
         */
        if (ObjectUtil.isNotEmpty(vmsManualDetailDtoList)) {

            for (int i = 0; i < vmsManualDetailDtoList.size(); i++) {
                String errMsg = "手工开票发票明细信息-第" + (i + 1) + "行：";
                VmsManualDetailDto detailDto = vmsManualDetailDtoList.get(i);

                // 参数校验
                String msg;
                boolean isError = false;

                // 发票行性质
                msg = checkStringParam(detailDto.getFphxz(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_FPHXZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 税收分类编码
                msg = checkStringParam(detailDto.getSphfwssflhbbm(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_SPHFWSSFLHBBM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 项目名称
                msg = checkStringParam(detailDto.getXmmc(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_XMMC);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 规格型号
                msg = checkStringParam(detailDto.getGgxh(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_GGXH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 计量单位
                msg = checkStringParam(detailDto.getDw(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_DW);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 数量
                msg = checkStringParam(detailDto.getSl(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_SL);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 单价（不含税）
                msg = checkStringParam(detailDto.getDj(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_DJ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 金额（不含税）
                msg = checkBigDecimalParam(detailDto.getJe(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_JE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 扣除额
                msg = checkBigDecimalParam(detailDto.getKce(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_KCE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 税率/征税率
                msg = checkBigDecimalParam(detailDto.getSlv(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_SLV);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 税额
                msg = checkBigDecimalParam(detailDto.getSe(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_SE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 计税方法
                msg = checkStringParam(detailDto.getJsff(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_JSFF);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 征税项目
                msg = checkStringParam(detailDto.getZsxm(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_ZSXM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 优惠政策标识
                msg = checkStringParam(detailDto.getYhzcbs(), CheckParamEnum.CHECK_VMSMANUALDETAILDTO_YHZCBS);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                if (isError) {
                    if (errMsg.endsWith(CommonConstant.STRING_COMMA)) {
                        errMsg = errMsg.substring(0, errMsg.lastIndexOf(CommonConstant.STRING_COMMA));
                    }
                    errMsgList.add(errMsg);
                }
            }

        }

        /**
         * 校验发票附加要素信息
         */
        if (ObjectUtil.isNotEmpty(vmsManualAddDtoList)) {

            for (int i = 0; i < vmsManualAddDtoList.size(); i++) {
                String errMsg = "手工开票发票附加要素信息-第" + (i + 1) + "行：";
                VmsManualAddDto addDto = vmsManualAddDtoList.get(i);

                // 参数校验
                String msg;
                boolean isError = false;

                // 附加要素名称
                msg = checkStringParam(addDto.getFjysmc(), CheckParamEnum.CHECK_VMSMANUALADDDTO_FJYSMC);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 附加要素类型
                msg = checkStringParam(addDto.getFjyslx(), CheckParamEnum.CHECK_VMSMANUALADDDTO_FJYSLX);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 附加要素值
                msg = checkStringParam(addDto.getFjysz(), CheckParamEnum.CHECK_VMSMANUALADDDTO_FJYSZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                if (isError) {
                    if (errMsg.endsWith(CommonConstant.STRING_COMMA)) {
                        errMsg = errMsg.substring(0, errMsg.lastIndexOf(CommonConstant.STRING_COMMA));
                    }
                    errMsgList.add(errMsg);
                }
            }
        }

        /**
         * 校验发票特定业务信息
         */
        if (ObjectUtil.isNotEmpty(vmsManualTdywDtoList)) {
            for (int i = 0; i < vmsManualTdywDtoList.size(); i++) {
                String errMsg = "手工开票发票特定业务信息-第" + (i + 1) + "行：";
                VmsManualTdywDto tdywDto = vmsManualTdywDtoList.get(i);

                // 参数校验
                String msg;
                boolean isError = false;

                // 不动产坐落地址（省）
                msg = checkStringParam(tdywDto.getBdczldzS(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_BDCZLDZS);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 不动产坐落地址（市）
                msg = checkStringParam(tdywDto.getBdczldzS1(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_BDCZLDZS1);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 不动产坐落地址（详细地址）
                msg = checkStringParam(tdywDto.getBdczldzXxdz(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_BDCZLDZXXDZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 租赁期起止
                msg = checkStringParam(tdywDto.getZlqqz(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_ZLQQZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 跨地（市）标志
                msg = checkStringParam(tdywDto.getKdsbz(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_KDSBZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 产权证书/不动产权证号
                msg = checkStringParam(tdywDto.getCqzsbh(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_CQZSBH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 不动产单位代码
                msg = checkStringParam(tdywDto.getBdcdwdm(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_BDCDWDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 网签合同备案编号
                msg = checkStringParam(tdywDto.getWqhtbabh(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_WQHTBABH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 土地增值税项目编号
                msg = checkStringParam(tdywDto.getTdzzsxmbh(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_TDZZSXMBH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 核定计税价格
                msg = checkBigDecimalParam(tdywDto.getHdjsjg(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_HDJSJG);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 实际成交含税金额
                msg = checkBigDecimalParam(tdywDto.getSjcjhsje(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_SJCJHSJE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 面积单位
                msg = checkStringParam(tdywDto.getMjdw(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_MJDW);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 多方共同购买标志
                msg = checkStringParam(tdywDto.getDfgtgmbz(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_DFGTGMBZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                if (CommonConstant.STR_Y.equals(tdywDto.getDfgtgmbz())) {
                    if (CollectionUtil.isNotEmpty(tdywDto.getTdywItemList())) {
                        for (int j = 0; j < tdywDto.getTdywItemList().size(); j++) {
                            VmsManualTdywItemDto tdywItemDto = tdywDto.getTdywItemList().get(j);
                            // 共同购买方
                            msg = checkStringParam(tdywItemDto.getGtgmf(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_GTGMF);
                            if (StringUtils.isNotBlank(msg)) {
                                errMsg = errMsg + "第" + (j + 1) + "行共同购买方：" + msg + CommonConstant.STRING_COMMA;
                                isError = true;
                            }

                            // 证件类型
                            msg = checkStringParam(tdywItemDto.getZjlx(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_ZJLX);
                            if (StringUtils.isNotBlank(msg)) {
                                errMsg = errMsg + "第" + (j + 1) + "行共同购买方：" + msg + CommonConstant.STRING_COMMA;
                                isError = true;
                            }

                            // 证件号码
                            msg = checkStringParam(tdywItemDto.getZjhm(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_ZJHM);
                            if (StringUtils.isNotBlank(msg)) {
                                errMsg = errMsg + "第" + (j + 1) + "行共同购买方：" + msg + CommonConstant.STRING_COMMA;
                                isError = true;
                            }
                        }
                    }
                }

                // 出行人序号
                msg = checkIntegerParam(tdywDto.getCxrxh(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_CXRXH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 出行人
                msg = checkStringParam(tdywDto.getCxr(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_CXR);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 出行人证件类型
                msg = checkStringParam(tdywDto.getCxrzjlxdm(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_CXRZJLXDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 有效身份证件号
                msg = checkStringParam(tdywDto.getSfzjhm(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_SFZJHM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 出行日期
                msg = checkStringParam(tdywDto.getChuxrq(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_CHUXRQ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 旅客出发地
                msg = checkStringParam(tdywDto.getCfd(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_CFD);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 旅客到达地
                msg = checkStringParam(tdywDto.getDdd(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_DDD);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 交通工具类型
                msg = checkStringParam(tdywDto.getJtgjlxdm(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_JTGJLXDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 座位等级
                msg = checkStringParam(tdywDto.getZwdj(), CheckParamEnum.CHECK_VMSMANUALTDYWDTO_ZWDJ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                if (isError) {
                    if (errMsg.endsWith(CommonConstant.STRING_COMMA)) {
                        errMsg = errMsg.substring(0, errMsg.lastIndexOf(CommonConstant.STRING_COMMA));
                    }
                    errMsgList.add(errMsg);
                }
            }
        }

        /**
         * 校验发票差额扣除信息
         */
        if (ObjectUtil.isNotEmpty(vmsManualCekcDtoList)) {
            for (int i = 0; i < vmsManualCekcDtoList.size(); i++) {
                String errMsg = "手工开票发票差额扣除信息-第" + (i + 1) + "行：";
                VmsManualCekcDto cekcDto = vmsManualCekcDtoList.get(i);

                // 参数校验
                String msg;
                boolean isError = false;

                // 凭证类型
                msg = checkStringParam(cekcDto.getPzlx(), CheckParamEnum.CHECK_VMSMANUALCEKCDTO_PZLX);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票代码
                msg = checkStringParam(cekcDto.getFpdm(), CheckParamEnum.CHECK_VMSMANUALCEKCDTO_FPDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票号码
                msg = checkStringParam(cekcDto.getFphm(), CheckParamEnum.CHECK_VMSMANUALCEKCDTO_FPHM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 差额凭证号码
                msg = checkStringParam(cekcDto.getCepzhm(), CheckParamEnum.CHECK_VMSMANUALCEKCDTO_CEPZHM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 开具日期
                msg = checkStringParam(cekcDto.getKjrq(), CheckParamEnum.CHECK_VMSMANUALCEKCDTO_KJRQ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 凭证合计金额
                msg = checkBigDecimalParam(cekcDto.getPzhjje(), CheckParamEnum.CHECK_VMSMANUALCEKCDTO_PZHJJE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 本次扣除金额
                msg = checkBigDecimalParam(cekcDto.getBckcje(), CheckParamEnum.CHECK_VMSMANUALCEKCDTO_BCKCJE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 备注
                msg = checkStringParam(cekcDto.getBz(), CheckParamEnum.CHECK_VMSMANUALCEKCDTO_BZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                if (isError) {
                    if (errMsg.endsWith(CommonConstant.STRING_COMMA)) {
                        errMsg = errMsg.substring(0, errMsg.lastIndexOf(CommonConstant.STRING_COMMA));
                    }
                    errMsgList.add(errMsg);
                }
            }
        }

        return errMsgList;
    }

    /**
     * Excel数据校验，如有错误则返回
     */
    private List<String> checkExcelData(List<VmsManualBaseExcel> rows1, List<VmsManualExtendExcel> rows2,
                                        List<VmsManualDetailExcel> rows3, List<VmsManualTdywExcel> rows4) {
        List<String> errMsgList = new ArrayList<>();

        /**
         * 校验Excel导入-发票主信息
         */
        if (CollectionUtil.isNotEmpty(rows1)) {
            for (int i = 0; i < rows1.size(); i++) {
                String errMsg = "手工开票基础信息-第" + (i + 4) + "行：";
                VmsManualBaseExcel vmsManualBaseExcel = rows1.get(i);

                // 校验String类型参数
                String msg;
                boolean isError = false;

                List<VmsManualDetailExcel> detailExcelList = rows3.stream().filter(a -> vmsManualBaseExcel.getXh().equals(a.getXh())).collect(Collectors.toList());
                if (CollectionUtil.isEmpty(detailExcelList)) {
                    errMsg = errMsg + "发票明细sheet页无对应明细信息" + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购买方自然人标志
                msg = checkStringParam(vmsManualBaseExcel.getGmfzrrbz(), CheckParamEnum.CHECK_VMSMANUALBASEEXCEL_GMFZRRBZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购方名称
                msg = checkStringParam(vmsManualBaseExcel.getGmfmc(), CheckParamEnum.CHECK_VMSMANUALBASEEXCEL_GMFMC);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购方纳税人识别号
                msg = checkStringParam(vmsManualBaseExcel.getGmfnsrsbh(), CheckParamEnum.CHECK_VMSMANUALBASEEXCEL_GMFNSRSBH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 特定要素
                msg = checkStringParam(vmsManualBaseExcel.getTdys(), CheckParamEnum.CHECK_VMSMANUALBASEEXCEL_TDYS);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 特定要素仅允许单行明细
                if (StringUtils.isNotBlank(vmsManualBaseExcel.getTdys()) && detailExcelList.size() != 1) {
                    errMsg = errMsg + TdysEnum.getNameByCode(vmsManualBaseExcel.getTdys().substring(0,2)) + "仅支持单行开具！" + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 单号类型
                msg = checkStringParam(vmsManualBaseExcel.getDhlx(), CheckParamEnum.CHECK_VMSMANUALBASEEXCEL_DHLX);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 单号
                msg = checkStringParam(vmsManualBaseExcel.getDh(), CheckParamEnum.CHECK_VMSMANUALBASEEXCEL_DH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 备注
                msg = checkStringParam(vmsManualBaseExcel.getBz(), CheckParamEnum.CHECK_VMSMANUALBASEEXCEL_BZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                if (isError) {
                    if (errMsg.endsWith(CommonConstant.STRING_COMMA)) {
                        errMsg = errMsg.substring(0, errMsg.lastIndexOf(CommonConstant.STRING_COMMA));
                    }
                    errMsgList.add(errMsg);
                }
            }
        }

        /**
         * Excel导入-发票非必填字段扩展信息
         */
        if (CollectionUtil.isNotEmpty(rows2)) {
            for (int i = 0; i < rows2.size(); i++) {
                String errMsg = "手工开票次要信息-第" + (i + 4) + "行：";
                VmsManualExtendExcel vmsManualExtendExcel = rows2.get(i);

                // 校验String类型参数
                String msg;
                boolean isError = false;

                // 增值税即征即退代码
                msg = checkStringParam(vmsManualExtendExcel.getZzsjzjtdm(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_ZZSJZJTDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 收购发票类型代码
                msg = checkStringParam(vmsManualExtendExcel.getSgfplxdm(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_SGFPLXDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 出口业务适用政策代码
                msg = checkStringParam(vmsManualExtendExcel.getCkywsyzcdm(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_CKYWSYZCDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购方地址
                msg = checkStringParam(vmsManualExtendExcel.getGmfdz(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_GMFDZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购方电话
                msg = checkStringParam(vmsManualExtendExcel.getGmfdh(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_GMFDH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购方开户行
                msg = checkStringParam(vmsManualExtendExcel.getGmfkhh(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_GMFKHH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购买方账号
                msg = checkStringParam(vmsManualExtendExcel.getGmfzh(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_GMFZH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 是否展示购买方银行账号标签
                msg = checkStringParam(vmsManualExtendExcel.getSfzsgmfyhzhbq(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_SFZSGMFYHZHBQ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购买方经办人姓名
                msg = checkStringParam(vmsManualExtendExcel.getGmfjbr(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_GMFJBR);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购买方经办人证件号码
                msg = checkStringParam(vmsManualExtendExcel.getJbrsfzjhm(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_JBRSFZJHM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购买方经办人联系电话
                msg = checkStringParam(vmsManualExtendExcel.getGmfjbrlxdh(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_GMFJBRLXDH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 销售方地址
                msg = checkStringParam(vmsManualExtendExcel.getXsfdz(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_XSFDZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 销售方电话
                msg = checkStringParam(vmsManualExtendExcel.getXsfdh(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_XSFDH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 销售方开户行
                msg = checkStringParam(vmsManualExtendExcel.getXsfkhh(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_XSFKHH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 销售方账号
                msg = checkStringParam(vmsManualExtendExcel.getXsfzh(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_XSFZH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 是否展示销售方银行账号标签
                msg = checkStringParam(vmsManualExtendExcel.getSfzsxsfyhzhbq(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_SFZSXSFYHZHBQ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 收款银行名称
                msg = checkStringParam(vmsManualExtendExcel.getSkyhmc(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_SKYHMC);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 收款银行账号
                msg = checkStringParam(vmsManualExtendExcel.getSkyhzh(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_SKYHZH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 结算方式
                msg = checkStringParam(vmsManualExtendExcel.getJsfs(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_JSFS);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 开票人证件类型
                msg = checkStringParam(vmsManualExtendExcel.getKprzjlx(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_KPRZJLX);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 开票人证件号码
                msg = checkStringParam(vmsManualExtendExcel.getKprzjhm(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_KPRZJHM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 收款人
                msg = checkStringParam(vmsManualExtendExcel.getSkrxm(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_SKRXM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 复核人
                msg = checkStringParam(vmsManualExtendExcel.getFhrxm(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_FHRXM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 区域代码
                msg = checkStringParam(vmsManualExtendExcel.getQydm(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_QYDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 应税行为发生地
                msg = checkStringParam(vmsManualExtendExcel.getYsxwfsd(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_YSXWFSD);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 附加要素名称
                msg = checkStringParam(vmsManualExtendExcel.getFjysmc(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_FJYSMC);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 附加要素类型
                msg = checkStringParam(vmsManualExtendExcel.getFjyslx(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_FJYSLX);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 附加要素值
                msg = checkStringParam(vmsManualExtendExcel.getFjysz(), CheckParamEnum.CHECK_VMSMANUALEXTENDEXCEL_FJYSZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                if (isError) {
                    if (errMsg.endsWith(CommonConstant.STRING_COMMA)) {
                        errMsg = errMsg.substring(0, errMsg.lastIndexOf(CommonConstant.STRING_COMMA));
                    }
                    errMsgList.add(errMsg);
                }
            }
        }

        /**
         * Excel导入-发票明细信息
         */
        if (CollectionUtil.isNotEmpty(rows3)) {
            for (int i = 0; i < rows3.size(); i++) {
                String errMsg = "手工开票发票明细信息-第" + (i + 4) + "行：";
                VmsManualDetailExcel vmsManualDetailExcel = rows3.get(i);

                // 校验String类型参数
                String msg;
                boolean isError = false;

                // 企业商品及服务编码
                msg = checkStringParam(vmsManualDetailExcel.getCpbm(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_CPBM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票行性质
                msg = checkStringParam(vmsManualDetailExcel.getFphxz(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_FPHXZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 税收分类编码
                msg = checkStringParam(vmsManualDetailExcel.getSphfwssflhbbm(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_SPHFWSSFLHBBM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 项目名称
                msg = checkStringParam(vmsManualDetailExcel.getXmmc(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_XMMC);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 规格型号
                msg = checkStringParam(vmsManualDetailExcel.getGgxh(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_GGXH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 计量单位
                msg = checkStringParam(vmsManualDetailExcel.getDw(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_DW);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 数量
                msg = checkStringParam(vmsManualDetailExcel.getSl(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_SL);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 单价（不含税）
                msg = checkStringParam(vmsManualDetailExcel.getDj(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_DJ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 金额（不含税）
                msg = checkBigDecimalParam(vmsManualDetailExcel.getJe(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_JE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 扣除额
                msg = checkBigDecimalParam(vmsManualDetailExcel.getKce(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_KCE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 税率/征税率
                msg = checkBigDecimalParam(vmsManualDetailExcel.getSlv(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_SLV);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 税额
                msg = checkBigDecimalParam(vmsManualDetailExcel.getSe(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_SE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 计税方法
                msg = checkStringParam(vmsManualDetailExcel.getJsff(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_JSFF);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 征税项目
                msg = checkStringParam(vmsManualDetailExcel.getZsxm(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_ZSXM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 优惠政策标识
                msg = checkStringParam(vmsManualDetailExcel.getYhzcbs(), CheckParamEnum.CHECK_VMSMANUALDETAILEXCEL_YHZCBS);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                if (isError) {
                    if (errMsg.endsWith(CommonConstant.STRING_COMMA)) {
                        errMsg = errMsg.substring(0, errMsg.lastIndexOf(CommonConstant.STRING_COMMA));
                    }
                    errMsgList.add(errMsg);
                }
            }
        }

        /**
         * Excel导入-发票特定业务信息
         */
        if (CollectionUtil.isNotEmpty(rows4)) {
            for (int i = 0; i < rows4.size(); i++) {
                String errMsg = "手工开票特定业务信息-第" + (i + 4) + "行：";
                VmsManualTdywExcel vmsManualTdywExcel = rows4.get(i);

                // 校验String类型参数
                String msg;
                boolean isError = false;

                // 不动产坐落地址（省）
                msg = checkStringParam(vmsManualTdywExcel.getBdczldzS(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_BDCZLDZS);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 不动产坐落地址（市）
                msg = checkStringParam(vmsManualTdywExcel.getBdczldzS1(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_BDCZLDZS1);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 不动产坐落地址（详细地址）
                msg = checkStringParam(vmsManualTdywExcel.getBdczldzXxdz(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_BDCZLDZXXDZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 租赁期起止
                msg = checkStringParam(vmsManualTdywExcel.getZlqqz(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_ZLQQZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 跨地（市）标志
                msg = checkStringParam(vmsManualTdywExcel.getKdsbz(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_KDSBZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 产权证书/不动产权证号
                msg = checkStringParam(vmsManualTdywExcel.getCqzsbh(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_CQZSBH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 不动产单位代码
                msg = checkStringParam(vmsManualTdywExcel.getBdcdwdm(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_BDCDWDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 网签合同备案编号
                msg = checkStringParam(vmsManualTdywExcel.getWqhtbabh(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_WQHTBABH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 土地增值税项目编号
                msg = checkStringParam(vmsManualTdywExcel.getTdzzsxmbh(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_TDZZSXMBH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 核定计税价格
                msg = checkBigDecimalParam(vmsManualTdywExcel.getHdjsjg(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_HDJSJG);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 实际成交含税金额
                msg = checkBigDecimalParam(vmsManualTdywExcel.getSjcjhsje(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_SJCJHSJE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 面积单位
                msg = checkStringParam(vmsManualTdywExcel.getMjdw(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_MJDW);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 多方共同购买标志
                msg = checkStringParam(vmsManualTdywExcel.getDfgtgmbz(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_DFGTGMBZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 共同购买方
                msg = checkStringParam(vmsManualTdywExcel.getGtgmf(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_GTGMF);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 证件类型
                msg = checkStringParam(vmsManualTdywExcel.getZjlx(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_ZJLX);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 证件号码
                msg = checkStringParam(vmsManualTdywExcel.getZjhm(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_ZJHM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 出行人序号
                msg = checkIntegerParam(vmsManualTdywExcel.getCxrxh(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_CXRXH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 出行人
                msg = checkStringParam(vmsManualTdywExcel.getCxr(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_CXR);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 出行人证件类型
                msg = checkStringParam(vmsManualTdywExcel.getCxrzjlxdm(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_CXRZJLXDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 有效身份证件号
                msg = checkStringParam(vmsManualTdywExcel.getSfzjhm(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_SFZJHM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 出行日期
                msg = checkStringParam(vmsManualTdywExcel.getChuxrq(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_CHUXRQ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 旅客出发地
                msg = checkStringParam(vmsManualTdywExcel.getCfd(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_CFD);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 旅客到达地
                msg = checkStringParam(vmsManualTdywExcel.getDdd(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_DDD);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 交通工具类型
                msg = checkStringParam(vmsManualTdywExcel.getJtgjlxdm(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_JTGJLXDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 座位等级
                msg = checkStringParam(vmsManualTdywExcel.getZwdj(), CheckParamEnum.CHECK_VMSMANUALTDYWEXCEL_ZWDJ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                if (isError) {
                    if (errMsg.endsWith(CommonConstant.STRING_COMMA)) {
                        errMsg = errMsg.substring(0, errMsg.lastIndexOf(CommonConstant.STRING_COMMA));
                    }
                    errMsgList.add(errMsg);
                }
            }
        }

        return errMsgList;
    }

    /**
     * 校验String类型参数
     *
     * @param param          待校验的参数
     * @param checkParamEnum 数据校验枚举类
     * @return 如校验不通过返回错误信息
     */
    private String checkStringParam(String param, CheckParamEnum checkParamEnum) {
        List<String> errorMsg = new ArrayList<>();

        // 如果字段为空，校验是否必填
        if (StringUtils.isBlank(param)) {
            if (checkParamEnum.getRequired()) {
                errorMsg.add(checkParamEnum.getParamName() + "为必填信息项");
                return String.join("，", errorMsg);
            }
            return String.join("，", errorMsg);
        }

        // 校验是否为固定格式
        if (checkParamEnum.getFixedFormal()) {
            String[] split = param.split("：");
            if (split.length != 2) {
                errorMsg.add(checkParamEnum.getParamName() + "格式不正确，请选择单元格下拉框列表数据");
            }
        }

        // 校验数据最大长度
        if (checkParamEnum.getMaxLength() != 0) {
            if (param.length() > checkParamEnum.getMaxLength()) {
                errorMsg.add(checkParamEnum.getParamName() + "数据不合法,最大长度为" + checkParamEnum.getMaxLength());
            }
        }

        return String.join("，", errorMsg);
    }

    /**
     * 校验BigDecimal类型参数
     *
     * @param param          待校验的参数
     * @param checkParamEnum 数据校验枚举类
     * @return 如校验不通过返回错误信息
     */
    private String checkBigDecimalParam(BigDecimal param, CheckParamEnum checkParamEnum) {
        List<String> errorMsg = new ArrayList<>();

        // 如果字段为空，校验是否必填
        if (null == param) {
            if (checkParamEnum.getRequired()) {
                errorMsg.add(checkParamEnum.getParamName() + "为必填信息项");
                return String.join("，", errorMsg);
            }
            return String.join("，", errorMsg);
        }

        // 校验数据整数位和小数位最大长度
        if (StringUtils.isNotBlank(checkParamEnum.getNumberFormat())) {
            String[] split = checkParamEnum.getNumberFormat().split(",");
            if (split.length == 2) {
                // 获取整数位和小数位最大长度
                int maxIntegerDigits = Integer.parseInt(split[0]);
                int maxDecimalDigits = Integer.parseInt(split[1]);
                // 去掉尾部多余的0
                BigDecimal bigDecimal = param.stripTrailingZeros();
                // 获取参数的整数位数和小数位数
                int integerDigits = bigDecimal.precision() - bigDecimal.scale();
                int decimalDigits = Math.max(bigDecimal.scale(), 0);

                // 判断是否满足最大长度限制
                if (integerDigits > maxIntegerDigits || decimalDigits > maxDecimalDigits) {
                    errorMsg.add(checkParamEnum.getParamName() + "数据不合法,整数位最大长度为" + maxIntegerDigits + ",小数位最大长度为" + maxDecimalDigits);
                }
            }
        }

        return String.join("，", errorMsg);
    }

    /**
     * 校验Integer类型参数
     *
     * @param param          待校验的参数
     * @param checkParamEnum 数据校验枚举类
     * @return 如校验不通过返回错误信息
     */
    private String checkIntegerParam(Integer param, CheckParamEnum checkParamEnum) {
        List<String> errorMsg = new ArrayList<>();

        // 如果字段为空，校验是否必填
        if (null == param) {
            if (checkParamEnum.getRequired()) {
                errorMsg.add(checkParamEnum.getParamName() + "为必填信息项");
                return String.join("，", errorMsg);
            }
            return String.join("，", errorMsg);
        }

        // 校验数据最大长度
        if (checkParamEnum.getMaxLength() != 0) {
            if (param.toString().length() > checkParamEnum.getMaxLength()) {
                errorMsg.add(checkParamEnum.getParamName() + "数据不合法,最大长度为" + checkParamEnum.getMaxLength());
            }
        }

        return String.join("，", errorMsg);
    }

}
